diff --git a/examples/GraphicsTest/main.cpp b/examples/GraphicsTest/main.cpp index d28511846..e967a930a 100644 --- a/examples/GraphicsTest/main.cpp +++ b/examples/GraphicsTest/main.cpp @@ -89,19 +89,13 @@ int main() return __LINE__; } - - - std::shared_ptr textureSampler = device->InstantiateTextureSampler({}); - std::shared_ptr material = std::make_shared(Nz::BasicMaterial::GetSettings()); material->EnableDepthBuffer(true); Nz::BasicMaterial basicMat(*material); basicMat.EnableAlphaTest(false); basicMat.SetAlphaMap(alphaTexture); - basicMat.SetAlphaSampler(textureSampler); basicMat.SetDiffuseMap(texture); - basicMat.SetDiffuseSampler(textureSampler); Nz::Model model(std::move(gfxMesh)); for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i) diff --git a/include/Nazara/Graphics/BasicMaterial.hpp b/include/Nazara/Graphics/BasicMaterial.hpp index ff4815732..8142e9cc0 100644 --- a/include/Nazara/Graphics/BasicMaterial.hpp +++ b/include/Nazara/Graphics/BasicMaterial.hpp @@ -24,11 +24,11 @@ namespace Nz inline void EnableAlphaTest(bool alphaTest); inline const std::shared_ptr& GetAlphaMap() const; - inline const std::shared_ptr& GetAlphaSampler() const; + inline const TextureSamplerInfo& GetAlphaSampler() const; float GetAlphaTestThreshold() const; Color GetDiffuseColor() const; inline const std::shared_ptr& GetDiffuseMap() const; - inline const std::shared_ptr& GetDiffuseSampler() const; + inline const TextureSamplerInfo& GetDiffuseSampler() const; inline bool HasAlphaMap() const; inline bool HasAlphaTest() const; @@ -37,11 +37,11 @@ namespace Nz inline bool HasDiffuseMap() const; inline void SetAlphaMap(std::shared_ptr alphaMap); - inline void SetAlphaSampler(std::shared_ptr alphaSampler); + inline void SetAlphaSampler(TextureSamplerInfo alphaSampler); void SetAlphaTestThreshold(float alphaThreshold); void SetDiffuseColor(const Color& diffuse); inline void SetDiffuseMap(std::shared_ptr diffuseMap); - inline void SetDiffuseSampler(std::shared_ptr diffuseSampler); + inline void SetDiffuseSampler(TextureSamplerInfo diffuseSampler); static inline const UniformOffsets& GetOffsets(); static inline const std::shared_ptr& GetSettings(); diff --git a/include/Nazara/Graphics/BasicMaterial.inl b/include/Nazara/Graphics/BasicMaterial.inl index 8eb32ff7f..4ed3ad8ca 100644 --- a/include/Nazara/Graphics/BasicMaterial.inl +++ b/include/Nazara/Graphics/BasicMaterial.inl @@ -35,7 +35,7 @@ namespace Nz return m_material.GetTexture(m_textureIndexes.alpha); } - inline const std::shared_ptr& BasicMaterial::GetAlphaSampler() const + inline const TextureSamplerInfo& BasicMaterial::GetAlphaSampler() const { NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot"); return m_material.GetTextureSampler(m_textureIndexes.alpha); @@ -47,7 +47,7 @@ namespace Nz return m_material.GetTexture(m_textureIndexes.diffuse); } - inline const std::shared_ptr& BasicMaterial::GetDiffuseSampler() const + inline const TextureSamplerInfo& BasicMaterial::GetDiffuseSampler() const { NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot"); return m_material.GetTextureSampler(m_textureIndexes.diffuse); @@ -88,7 +88,7 @@ namespace Nz m_material.EnableCondition(m_conditionIndexes.hasAlphaMap, hasAlphaMap); } - inline void BasicMaterial::SetAlphaSampler(std::shared_ptr alphaSampler) + inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler) { NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); m_material.SetTextureSampler(m_textureIndexes.alpha, std::move(alphaSampler)); @@ -104,7 +104,7 @@ namespace Nz m_material.EnableCondition(m_conditionIndexes.hasDiffuseMap, hasDiffuseMap); } - inline void BasicMaterial::SetDiffuseSampler(std::shared_ptr diffuseSampler) + inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler) { NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); m_material.SetTextureSampler(m_textureIndexes.diffuse, std::move(diffuseSampler)); diff --git a/include/Nazara/Graphics/Graphics.hpp b/include/Nazara/Graphics/Graphics.hpp index 954719f15..4f6f5115b 100644 --- a/include/Nazara/Graphics/Graphics.hpp +++ b/include/Nazara/Graphics/Graphics.hpp @@ -9,8 +9,10 @@ #include #include +#include #include #include +#include namespace Nz { @@ -30,6 +32,7 @@ namespace Nz ~Graphics(); inline RenderDevice& GetRenderDevice(); + inline TextureSamplerCache& GetSamplerCache(); inline const std::shared_ptr& GetViewerDataUBO(); struct Config @@ -38,6 +41,7 @@ namespace Nz }; private: + std::optional m_samplerCache; std::shared_ptr m_viewerDataUBO; std::shared_ptr m_renderDevice; diff --git a/include/Nazara/Graphics/Graphics.inl b/include/Nazara/Graphics/Graphics.inl index 35023cfc5..a4e581e5a 100644 --- a/include/Nazara/Graphics/Graphics.inl +++ b/include/Nazara/Graphics/Graphics.inl @@ -12,6 +12,11 @@ namespace Nz return *m_renderDevice; } + inline TextureSamplerCache& Graphics::GetSamplerCache() + { + return *m_samplerCache; + } + inline const std::shared_ptr& Graphics::GetViewerDataUBO() { return m_viewerDataUBO; diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp index 13569061c..3e2d24ce1 100644 --- a/include/Nazara/Graphics/Material.hpp +++ b/include/Nazara/Graphics/Material.hpp @@ -66,7 +66,7 @@ namespace Nz inline const std::shared_ptr& GetShader(ShaderStageType shaderStage) const; inline BlendFunc GetSrcBlend() const; inline const std::shared_ptr& GetTexture(std::size_t textureIndex) const; - inline const std::shared_ptr& GetTextureSampler(std::size_t textureIndex) const; + inline const TextureSamplerInfo& GetTextureSampler(std::size_t textureIndex) const; inline const std::shared_ptr& GetUniformBuffer(std::size_t bufferIndex) const; inline std::vector& GetUniformBufferData(std::size_t bufferIndex); inline const std::vector& GetUniformBufferConstData(std::size_t bufferIndex); @@ -96,7 +96,7 @@ namespace Nz inline void SetUniformBuffer(std::size_t bufferIndex, std::shared_ptr uniformBuffer); inline void SetSrcBlend(BlendFunc func); inline void SetTexture(std::size_t textureIndex, std::shared_ptr texture); - inline void SetTextureSampler(std::size_t textureIndex, std::shared_ptr sampler); + inline void SetTextureSampler(std::size_t textureIndex, TextureSamplerInfo samplerInfo); void UpdateShaderBinding(ShaderBinding& shaderBinding) const; @@ -106,12 +106,14 @@ namespace Nz private: inline void InvalidatePipeline(); inline void InvalidateShaderBinding(); + inline void InvalidateTextureSampler(std::size_t textureIndex); inline void UpdatePipeline() const; struct MaterialTexture { - std::shared_ptr sampler; + mutable std::shared_ptr sampler; std::shared_ptr texture; + TextureSamplerInfo samplerInfo; }; struct UniformBuffer diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl index 4d16ec19e..ddf82a7ce 100644 --- a/include/Nazara/Graphics/Material.inl +++ b/include/Nazara/Graphics/Material.inl @@ -436,10 +436,10 @@ namespace Nz return m_textures[textureIndex].texture; } - inline const std::shared_ptr& 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"); - return m_textures[textureIndex].sampler; + return m_textures[textureIndex].samplerInfo; } inline const std::shared_ptr& Material::GetUniformBuffer(std::size_t bufferIndex) const @@ -695,13 +695,13 @@ namespace Nz } } - inline void Material::SetTextureSampler(std::size_t textureIndex, std::shared_ptr sampler) + inline void Material::SetTextureSampler(std::size_t textureIndex, TextureSamplerInfo samplerInfo) { 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); - InvalidateShaderBinding(); + m_textures[textureIndex].samplerInfo = std::move(samplerInfo); + InvalidateTextureSampler(textureIndex); } } @@ -731,6 +731,14 @@ namespace Nz //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 { for (auto& shader : m_pipelineInfo.shaders) diff --git a/include/Nazara/Graphics/TextureSamplerCache.hpp b/include/Nazara/Graphics/TextureSamplerCache.hpp new file mode 100644 index 000000000..71a7e4c5d --- /dev/null +++ b/include/Nazara/Graphics/TextureSamplerCache.hpp @@ -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 +#include +#include +#include + +namespace Nz +{ + class RenderDevice; + + class NAZARA_GRAPHICS_API TextureSamplerCache + { + public: + inline TextureSamplerCache(std::shared_ptr device); + TextureSamplerCache(const TextureSamplerCache&) = delete; + TextureSamplerCache(TextureSamplerCache&&) = delete; + ~TextureSamplerCache() = default; + + const std::shared_ptr& Get(const TextureSamplerInfo& info); + + TextureSamplerCache& operator=(const TextureSamplerCache&) = delete; + TextureSamplerCache& operator=(TextureSamplerCache&&) = delete; + + private: + std::shared_ptr m_device; + std::unordered_map> m_samplers; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/TextureSamplerCache.inl b/include/Nazara/Graphics/TextureSamplerCache.inl new file mode 100644 index 000000000..e72e3c4cd --- /dev/null +++ b/include/Nazara/Graphics/TextureSamplerCache.inl @@ -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 +#include +#include + +namespace Nz +{ + inline TextureSamplerCache::TextureSamplerCache(std::shared_ptr device) : + m_device(std::move(device)) + { + } +} + +#include diff --git a/include/Nazara/Renderer/TextureSampler.hpp b/include/Nazara/Renderer/TextureSampler.hpp index e050298c3..2b7977101 100644 --- a/include/Nazara/Renderer/TextureSampler.hpp +++ b/include/Nazara/Renderer/TextureSampler.hpp @@ -22,6 +22,9 @@ namespace Nz SamplerWrap wrapModeU = SamplerWrap_Clamp; SamplerWrap wrapModeV = 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 @@ -37,6 +40,9 @@ namespace Nz }; } +template<> +struct std::hash; + #include #endif // NAZARA_TEXTURE_HPP diff --git a/include/Nazara/Renderer/TextureSampler.inl b/include/Nazara/Renderer/TextureSampler.inl index a741958f0..a7f802bcb 100644 --- a/include/Nazara/Renderer/TextureSampler.inl +++ b/include/Nazara/Renderer/TextureSampler.inl @@ -3,10 +3,60 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include 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 +{ + 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 diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index aa2deb383..ebbd447d7 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -39,6 +39,8 @@ namespace Nz if (!m_renderDevice) throw std::runtime_error("failed to instantiate render device"); + m_samplerCache.emplace(m_renderDevice); + MaterialPipeline::Initialize(); Nz::PredefinedViewerData viewerUboOffsets = Nz::PredefinedViewerData::GetOffsets(); diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp index 4f12980b7..77ed2dd3c 100644 --- a/src/Nazara/Graphics/Material.cpp +++ b/src/Nazara/Graphics/Material.cpp @@ -63,7 +63,14 @@ namespace Nz 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({ bindingIndex, diff --git a/src/Nazara/Graphics/TextureSamplerCache.cpp b/src/Nazara/Graphics/TextureSamplerCache.cpp new file mode 100644 index 000000000..d211a9a36 --- /dev/null +++ b/src/Nazara/Graphics/TextureSamplerCache.cpp @@ -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 +#include +#include + +namespace Nz +{ + const std::shared_ptr& 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; + } +} diff --git a/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp b/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp index 3d0027332..cc8a768c0 100644 --- a/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp +++ b/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp @@ -55,13 +55,13 @@ namespace Nz 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)) - 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)) - 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()) - 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.alignedOffset = 0;