Graphics: Improve TextureSampler handling

This commit is contained in:
Jérôme Leclercq 2021-01-27 18:50:49 +01:00
parent 78c3f57333
commit b9151d8a7a
15 changed files with 181 additions and 27 deletions

View File

@ -89,19 +89,13 @@ int main()
return __LINE__; return __LINE__;
} }
std::shared_ptr<Nz::TextureSampler> textureSampler = device->InstantiateTextureSampler({});
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>(Nz::BasicMaterial::GetSettings()); std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>(Nz::BasicMaterial::GetSettings());
material->EnableDepthBuffer(true); material->EnableDepthBuffer(true);
Nz::BasicMaterial basicMat(*material); Nz::BasicMaterial basicMat(*material);
basicMat.EnableAlphaTest(false); basicMat.EnableAlphaTest(false);
basicMat.SetAlphaMap(alphaTexture); basicMat.SetAlphaMap(alphaTexture);
basicMat.SetAlphaSampler(textureSampler);
basicMat.SetDiffuseMap(texture); basicMat.SetDiffuseMap(texture);
basicMat.SetDiffuseSampler(textureSampler);
Nz::Model model(std::move(gfxMesh)); Nz::Model model(std::move(gfxMesh));
for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i) for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i)

View File

@ -24,11 +24,11 @@ namespace Nz
inline void EnableAlphaTest(bool alphaTest); inline void EnableAlphaTest(bool alphaTest);
inline const std::shared_ptr<Texture>& GetAlphaMap() const; inline const std::shared_ptr<Texture>& GetAlphaMap() const;
inline const std::shared_ptr<TextureSampler>& GetAlphaSampler() const; inline const TextureSamplerInfo& GetAlphaSampler() const;
float GetAlphaTestThreshold() const; float GetAlphaTestThreshold() const;
Color GetDiffuseColor() const; Color GetDiffuseColor() const;
inline const std::shared_ptr<Texture>& GetDiffuseMap() const; inline const std::shared_ptr<Texture>& GetDiffuseMap() const;
inline const std::shared_ptr<TextureSampler>& GetDiffuseSampler() const; inline const TextureSamplerInfo& GetDiffuseSampler() const;
inline bool HasAlphaMap() const; inline bool HasAlphaMap() const;
inline bool HasAlphaTest() const; inline bool HasAlphaTest() const;
@ -37,11 +37,11 @@ namespace Nz
inline bool HasDiffuseMap() const; inline bool HasDiffuseMap() const;
inline void SetAlphaMap(std::shared_ptr<Texture> alphaMap); inline void SetAlphaMap(std::shared_ptr<Texture> alphaMap);
inline void SetAlphaSampler(std::shared_ptr<TextureSampler> alphaSampler); inline void SetAlphaSampler(TextureSamplerInfo alphaSampler);
void SetAlphaTestThreshold(float alphaThreshold); void SetAlphaTestThreshold(float alphaThreshold);
void SetDiffuseColor(const Color& diffuse); void SetDiffuseColor(const Color& diffuse);
inline void SetDiffuseMap(std::shared_ptr<Texture> diffuseMap); inline void SetDiffuseMap(std::shared_ptr<Texture> diffuseMap);
inline void SetDiffuseSampler(std::shared_ptr<TextureSampler> diffuseSampler); inline void SetDiffuseSampler(TextureSamplerInfo diffuseSampler);
static inline const UniformOffsets& GetOffsets(); static inline const UniformOffsets& GetOffsets();
static inline const std::shared_ptr<MaterialSettings>& GetSettings(); static inline const std::shared_ptr<MaterialSettings>& GetSettings();

View File

@ -35,7 +35,7 @@ namespace Nz
return m_material.GetTexture(m_textureIndexes.alpha); return m_material.GetTexture(m_textureIndexes.alpha);
} }
inline const std::shared_ptr<TextureSampler>& BasicMaterial::GetAlphaSampler() const inline const TextureSamplerInfo& BasicMaterial::GetAlphaSampler() const
{ {
NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot"); NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot");
return m_material.GetTextureSampler(m_textureIndexes.alpha); return m_material.GetTextureSampler(m_textureIndexes.alpha);
@ -47,7 +47,7 @@ namespace Nz
return m_material.GetTexture(m_textureIndexes.diffuse); return m_material.GetTexture(m_textureIndexes.diffuse);
} }
inline const std::shared_ptr<TextureSampler>& BasicMaterial::GetDiffuseSampler() const inline const TextureSamplerInfo& BasicMaterial::GetDiffuseSampler() const
{ {
NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot"); NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot");
return m_material.GetTextureSampler(m_textureIndexes.diffuse); return m_material.GetTextureSampler(m_textureIndexes.diffuse);
@ -88,7 +88,7 @@ namespace Nz
m_material.EnableCondition(m_conditionIndexes.hasAlphaMap, hasAlphaMap); m_material.EnableCondition(m_conditionIndexes.hasAlphaMap, hasAlphaMap);
} }
inline void BasicMaterial::SetAlphaSampler(std::shared_ptr<TextureSampler> alphaSampler) inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler)
{ {
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
m_material.SetTextureSampler(m_textureIndexes.alpha, std::move(alphaSampler)); m_material.SetTextureSampler(m_textureIndexes.alpha, std::move(alphaSampler));
@ -104,7 +104,7 @@ namespace Nz
m_material.EnableCondition(m_conditionIndexes.hasDiffuseMap, hasDiffuseMap); m_material.EnableCondition(m_conditionIndexes.hasDiffuseMap, hasDiffuseMap);
} }
inline void BasicMaterial::SetDiffuseSampler(std::shared_ptr<TextureSampler> diffuseSampler) inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler)
{ {
NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot");
m_material.SetTextureSampler(m_textureIndexes.diffuse, std::move(diffuseSampler)); m_material.SetTextureSampler(m_textureIndexes.diffuse, std::move(diffuseSampler));

View File

@ -9,8 +9,10 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/Config.hpp> #include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/TextureSamplerCache.hpp>
#include <Nazara/Renderer/Renderer.hpp> #include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/RenderDevice.hpp> #include <Nazara/Renderer/RenderDevice.hpp>
#include <optional>
namespace Nz namespace Nz
{ {
@ -30,6 +32,7 @@ namespace Nz
~Graphics(); ~Graphics();
inline RenderDevice& GetRenderDevice(); inline RenderDevice& GetRenderDevice();
inline TextureSamplerCache& GetSamplerCache();
inline const std::shared_ptr<AbstractBuffer>& GetViewerDataUBO(); inline const std::shared_ptr<AbstractBuffer>& GetViewerDataUBO();
struct Config struct Config
@ -38,6 +41,7 @@ namespace Nz
}; };
private: private:
std::optional<TextureSamplerCache> m_samplerCache;
std::shared_ptr<AbstractBuffer> m_viewerDataUBO; std::shared_ptr<AbstractBuffer> m_viewerDataUBO;
std::shared_ptr<RenderDevice> m_renderDevice; std::shared_ptr<RenderDevice> m_renderDevice;

View File

@ -12,6 +12,11 @@ namespace Nz
return *m_renderDevice; return *m_renderDevice;
} }
inline TextureSamplerCache& Graphics::GetSamplerCache()
{
return *m_samplerCache;
}
inline const std::shared_ptr<AbstractBuffer>& Graphics::GetViewerDataUBO() inline const std::shared_ptr<AbstractBuffer>& Graphics::GetViewerDataUBO()
{ {
return m_viewerDataUBO; return m_viewerDataUBO;

View File

@ -66,7 +66,7 @@ namespace Nz
inline const std::shared_ptr<UberShader>& GetShader(ShaderStageType shaderStage) const; inline const std::shared_ptr<UberShader>& GetShader(ShaderStageType shaderStage) const;
inline BlendFunc GetSrcBlend() const; inline BlendFunc GetSrcBlend() const;
inline const std::shared_ptr<Texture>& GetTexture(std::size_t textureIndex) 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; inline const TextureSamplerInfo& GetTextureSampler(std::size_t textureIndex) const;
inline const std::shared_ptr<AbstractBuffer>& GetUniformBuffer(std::size_t bufferIndex) const; inline const std::shared_ptr<AbstractBuffer>& GetUniformBuffer(std::size_t bufferIndex) const;
inline std::vector<UInt8>& GetUniformBufferData(std::size_t bufferIndex); inline std::vector<UInt8>& GetUniformBufferData(std::size_t bufferIndex);
inline const std::vector<UInt8>& GetUniformBufferConstData(std::size_t bufferIndex); inline const std::vector<UInt8>& GetUniformBufferConstData(std::size_t bufferIndex);
@ -96,7 +96,7 @@ namespace Nz
inline void SetUniformBuffer(std::size_t bufferIndex, std::shared_ptr<AbstractBuffer> uniformBuffer); inline void SetUniformBuffer(std::size_t bufferIndex, std::shared_ptr<AbstractBuffer> uniformBuffer);
inline void SetSrcBlend(BlendFunc func); inline void SetSrcBlend(BlendFunc func);
inline void SetTexture(std::size_t textureIndex, std::shared_ptr<Texture> texture); inline void SetTexture(std::size_t textureIndex, std::shared_ptr<Texture> texture);
inline void SetTextureSampler(std::size_t textureIndex, std::shared_ptr<TextureSampler> sampler); inline void SetTextureSampler(std::size_t textureIndex, TextureSamplerInfo samplerInfo);
void UpdateShaderBinding(ShaderBinding& shaderBinding) const; void UpdateShaderBinding(ShaderBinding& shaderBinding) const;
@ -106,12 +106,14 @@ namespace Nz
private: private:
inline void InvalidatePipeline(); inline void InvalidatePipeline();
inline void InvalidateShaderBinding(); inline void InvalidateShaderBinding();
inline void InvalidateTextureSampler(std::size_t textureIndex);
inline void UpdatePipeline() const; inline void UpdatePipeline() const;
struct MaterialTexture struct MaterialTexture
{ {
std::shared_ptr<TextureSampler> sampler; mutable std::shared_ptr<TextureSampler> sampler;
std::shared_ptr<Texture> texture; std::shared_ptr<Texture> texture;
TextureSamplerInfo samplerInfo;
}; };
struct UniformBuffer struct UniformBuffer

View File

@ -436,10 +436,10 @@ namespace Nz
return m_textures[textureIndex].texture; return m_textures[textureIndex].texture;
} }
inline const std::shared_ptr<TextureSampler>& Material::GetTextureSampler(std::size_t textureIndex) const inline const TextureSamplerInfo& Material::GetTextureSampler(std::size_t textureIndex) const
{ {
NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index");
return m_textures[textureIndex].sampler; return m_textures[textureIndex].samplerInfo;
} }
inline const std::shared_ptr<AbstractBuffer>& Material::GetUniformBuffer(std::size_t bufferIndex) const inline const std::shared_ptr<AbstractBuffer>& Material::GetUniformBuffer(std::size_t bufferIndex) const
@ -695,13 +695,13 @@ namespace Nz
} }
} }
inline void Material::SetTextureSampler(std::size_t textureIndex, std::shared_ptr<TextureSampler> sampler) inline void Material::SetTextureSampler(std::size_t textureIndex, TextureSamplerInfo samplerInfo)
{ {
NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index");
if (m_textures[textureIndex].sampler != sampler) if (m_textures[textureIndex].samplerInfo != samplerInfo)
{ {
m_textures[textureIndex].sampler = std::move(sampler); m_textures[textureIndex].samplerInfo = std::move(samplerInfo);
InvalidateShaderBinding(); InvalidateTextureSampler(textureIndex);
} }
} }
@ -731,6 +731,14 @@ namespace Nz
//TODO //TODO
} }
inline void Material::InvalidateTextureSampler(std::size_t textureIndex)
{
assert(textureIndex < m_textures.size());
m_textures[textureIndex].sampler.reset();
InvalidateShaderBinding();
}
inline void Material::UpdatePipeline() const inline void Material::UpdatePipeline() const
{ {
for (auto& shader : m_pipelineInfo.shaders) for (auto& shader : m_pipelineInfo.shaders)

View File

@ -0,0 +1,40 @@
// 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_TEXTURESAMPLERCACHE_HPP
#define NAZARA_TEXTURESAMPLERCACHE_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Renderer/TextureSampler.hpp>
#include <unordered_map>
namespace Nz
{
class RenderDevice;
class NAZARA_GRAPHICS_API TextureSamplerCache
{
public:
inline TextureSamplerCache(std::shared_ptr<RenderDevice> device);
TextureSamplerCache(const TextureSamplerCache&) = delete;
TextureSamplerCache(TextureSamplerCache&&) = delete;
~TextureSamplerCache() = default;
const std::shared_ptr<TextureSampler>& Get(const TextureSamplerInfo& info);
TextureSamplerCache& operator=(const TextureSamplerCache&) = delete;
TextureSamplerCache& operator=(TextureSamplerCache&&) = delete;
private:
std::shared_ptr<RenderDevice> m_device;
std::unordered_map<TextureSamplerInfo, std::shared_ptr<TextureSampler>> m_samplers;
};
}
#include <Nazara/Graphics/TextureSamplerCache.inl>
#endif

View File

@ -0,0 +1,17 @@
// 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/TextureSamplerCache.hpp>
#include <functional>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline TextureSamplerCache::TextureSamplerCache(std::shared_ptr<RenderDevice> device) :
m_device(std::move(device))
{
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -22,6 +22,9 @@ namespace Nz
SamplerWrap wrapModeU = SamplerWrap_Clamp; SamplerWrap wrapModeU = SamplerWrap_Clamp;
SamplerWrap wrapModeV = SamplerWrap_Clamp; SamplerWrap wrapModeV = SamplerWrap_Clamp;
SamplerWrap wrapModeW = SamplerWrap_Clamp; SamplerWrap wrapModeW = SamplerWrap_Clamp;
inline bool operator==(const TextureSamplerInfo& samplerInfo) const;
inline bool operator!=(const TextureSamplerInfo& samplerInfo) const;
}; };
class NAZARA_RENDERER_API TextureSampler class NAZARA_RENDERER_API TextureSampler
@ -37,6 +40,9 @@ namespace Nz
}; };
} }
template<>
struct std::hash<Nz::TextureSamplerInfo>;
#include <Nazara/Renderer/TextureSampler.inl> #include <Nazara/Renderer/TextureSampler.inl>
#endif // NAZARA_TEXTURE_HPP #endif // NAZARA_TEXTURE_HPP

View File

@ -3,10 +3,60 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/TextureSampler.hpp> #include <Nazara/Renderer/TextureSampler.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <Nazara/Renderer/Debug.hpp> #include <Nazara/Renderer/Debug.hpp>
namespace Nz namespace Nz
{ {
inline bool TextureSamplerInfo::operator==(const TextureSamplerInfo& samplerInfo) const
{
if (!NumberEquals(anisotropyLevel, samplerInfo.anisotropyLevel, 0.99f))
return false;
if (magFilter != samplerInfo.magFilter)
return false;
if (minFilter != samplerInfo.minFilter)
return false;
if (mipmapMode != samplerInfo.mipmapMode)
return false;
if (wrapModeU != samplerInfo.wrapModeU)
return false;
if (wrapModeV != samplerInfo.wrapModeV)
return false;
if (wrapModeW != samplerInfo.wrapModeW)
return false;
return true;
}
inline bool TextureSamplerInfo::operator!=(const TextureSamplerInfo& samplerInfo) const
{
return !operator==(samplerInfo);
}
} }
template<>
struct std::hash<Nz::TextureSamplerInfo>
{
std::size_t operator()(const Nz::TextureSamplerInfo& sampler) const
{
std::size_t seed = 0;
Nz::HashCombine(seed, sampler.anisotropyLevel);
Nz::HashCombine(seed, sampler.magFilter);
Nz::HashCombine(seed, sampler.minFilter);
Nz::HashCombine(seed, sampler.mipmapMode);
Nz::HashCombine(seed, sampler.wrapModeU);
Nz::HashCombine(seed, sampler.wrapModeV);
Nz::HashCombine(seed, sampler.wrapModeW);
return seed;
}
};
#include <Nazara/Renderer/DebugOff.hpp> #include <Nazara/Renderer/DebugOff.hpp>

View File

@ -39,6 +39,8 @@ namespace Nz
if (!m_renderDevice) if (!m_renderDevice)
throw std::runtime_error("failed to instantiate render device"); throw std::runtime_error("failed to instantiate render device");
m_samplerCache.emplace(m_renderDevice);
MaterialPipeline::Initialize(); MaterialPipeline::Initialize();
Nz::PredefinedViewerData viewerUboOffsets = Nz::PredefinedViewerData::GetOffsets(); Nz::PredefinedViewerData viewerUboOffsets = Nz::PredefinedViewerData::GetOffsets();

View File

@ -63,7 +63,14 @@ namespace Nz
for (const auto& textureSlot : m_textures) for (const auto& textureSlot : m_textures)
{ {
if (textureSlot.texture && textureSlot.sampler) if (!textureSlot.sampler)
{
TextureSamplerCache& samplerCache = Graphics::Instance()->GetSamplerCache();
textureSlot.sampler = samplerCache.Get(textureSlot.samplerInfo);
}
//TODO: Use "missing" texture
if (textureSlot.texture)
{ {
bindings.push_back({ bindings.push_back({
bindingIndex, bindingIndex,

View File

@ -0,0 +1,19 @@
// 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/TextureSamplerCache.hpp>
#include <Nazara/Renderer/RenderDevice.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
const std::shared_ptr<TextureSampler>& TextureSamplerCache::Get(const TextureSamplerInfo& info)
{
auto it = m_samplers.find(info);
if (it == m_samplers.end())
it = m_samplers.emplace(info, m_device->InstantiateTextureSampler(info)).first;
return it->second;
}
}

View File

@ -55,13 +55,13 @@ namespace Nz
VkMemoryRequirements requirement = newBlock.buffer.GetMemoryRequirements(); VkMemoryRequirements requirement = newBlock.buffer.GetMemoryRequirements();
if (!newBlock.blockMemory.Create(m_device, requirement.size, requirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) if (!newBlock.blockMemory.Create(m_device, requirement.size, requirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
throw std::runtime_error("Failed to allocate block memory: " + TranslateVulkanError(newBlock.blockMemory.GetLastErrorCode())); throw std::runtime_error("failed to allocate block memory: " + TranslateVulkanError(newBlock.blockMemory.GetLastErrorCode()));
if (!newBlock.buffer.BindBufferMemory(newBlock.blockMemory)) if (!newBlock.buffer.BindBufferMemory(newBlock.blockMemory))
throw std::runtime_error("Failed to bind buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); throw std::runtime_error("failed to bind buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode()));
if (!newBlock.blockMemory.Map()) if (!newBlock.blockMemory.Map())
throw std::runtime_error("Failed to map buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); throw std::runtime_error("failed to map buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode()));
bestBlock.block = &m_blocks.emplace_back(std::move(newBlock)); bestBlock.block = &m_blocks.emplace_back(std::move(newBlock));
bestBlock.alignedOffset = 0; bestBlock.alignedOffset = 0;