From 19783f775541633862cb3f41b1acc98dab0c8a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 22 Jan 2021 23:31:54 +0100 Subject: [PATCH] Graphics/Material: Rework UBO handling --- include/Nazara/Graphics/Material.hpp | 20 ++++++-- include/Nazara/Graphics/Material.inl | 42 +++++++++++++--- src/Nazara/Graphics/BasicMaterial.cpp | 18 ++++--- src/Nazara/Graphics/Material.cpp | 50 +++++++++++++++++-- src/Nazara/Graphics/PhongLightingMaterial.cpp | 36 ++++++------- 5 files changed, 123 insertions(+), 43 deletions(-) diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp index 3a7223a62..13569061c 100644 --- a/include/Nazara/Graphics/Material.hpp +++ b/include/Nazara/Graphics/Material.hpp @@ -67,13 +67,13 @@ namespace Nz 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 UniformBufferRef& GetUniformBuffer(std::size_t bufferIndex); - inline const UniformBufferRef& GetUniformBuffer(std::size_t bufferIndex) 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); inline bool HasTexture(std::size_t textureIndex) const; inline bool HasVertexColor() const; - inline bool IsAlphaTestEnabled() const; inline bool IsBlendingEnabled() const; inline bool IsColorWriteEnabled() const; inline bool IsConditionEnabled(std::size_t conditionIndex) const; @@ -93,16 +93,19 @@ namespace Nz inline void SetFaceFilling(FaceFilling filling); inline void SetLineWidth(float lineWidth); inline void SetPointSize(float pointSize); - inline void SetUniformBuffer(std::size_t bufferIndex, UniformBufferRef uniformBuffer); + 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); + void UpdateShaderBinding(ShaderBinding& shaderBinding) const; + // Signals: NazaraSignal(OnMaterialRelease, const Material* /*material*/); private: inline void InvalidatePipeline(); + inline void InvalidateShaderBinding(); inline void UpdatePipeline() const; struct MaterialTexture @@ -111,9 +114,16 @@ namespace Nz std::shared_ptr texture; }; + struct UniformBuffer + { + std::shared_ptr buffer; + std::vector data; + bool dataInvalidated = true; + }; + std::shared_ptr m_settings; std::vector m_textures; - std::vector m_uniformBuffers; + std::vector m_uniformBuffers; mutable std::shared_ptr m_pipeline; UInt64 m_enabledConditions; mutable MaterialPipelineInfo m_pipelineInfo; diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl index 036ad2b6e..4d16ec19e 100644 --- a/include/Nazara/Graphics/Material.inl +++ b/include/Nazara/Graphics/Material.inl @@ -442,16 +442,24 @@ namespace Nz return m_textures[textureIndex].sampler; } - inline UniformBufferRef& Material::GetUniformBuffer(std::size_t bufferIndex) + inline const std::shared_ptr& Material::GetUniformBuffer(std::size_t bufferIndex) const { NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index"); - return m_uniformBuffers[bufferIndex]; + return m_uniformBuffers[bufferIndex].buffer; } - inline const UniformBufferRef& Material::GetUniformBuffer(std::size_t bufferIndex) const + inline std::vector& Material::GetUniformBufferData(std::size_t bufferIndex) { NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index"); - return m_uniformBuffers[bufferIndex]; + UniformBuffer& uboEntry = m_uniformBuffers[bufferIndex]; + uboEntry.dataInvalidated = true; + return uboEntry.data; + } + + inline const std::vector& Material::GetUniformBufferConstData(std::size_t bufferIndex) + { + NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index"); + return m_uniformBuffers[bufferIndex].data; } inline bool Material::HasTexture(std::size_t textureIndex) const @@ -666,22 +674,35 @@ namespace Nz InvalidatePipeline(); } - inline void Material::SetUniformBuffer(std::size_t bufferIndex, UniformBufferRef uniformBuffer) + inline void Material::SetUniformBuffer(std::size_t bufferIndex, std::shared_ptr uniformBuffer) { NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid shared uniform buffer index"); - m_uniformBuffers[bufferIndex] = std::move(uniformBuffer); + if (m_uniformBuffers[bufferIndex].buffer != uniformBuffer) + { + m_uniformBuffers[bufferIndex].buffer = std::move(uniformBuffer); + m_uniformBuffers[bufferIndex].dataInvalidated = true; + InvalidateShaderBinding(); + } } inline void Material::SetTexture(std::size_t textureIndex, std::shared_ptr texture) { NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); - m_textures[textureIndex].texture = std::move(texture); + if (m_textures[textureIndex].texture != texture) + { + m_textures[textureIndex].texture = std::move(texture); + InvalidateShaderBinding(); + } } inline void Material::SetTextureSampler(std::size_t textureIndex, std::shared_ptr sampler) { NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); - m_textures[textureIndex].sampler = std::move(sampler); + if (m_textures[textureIndex].sampler != sampler) + { + m_textures[textureIndex].sampler = std::move(sampler); + InvalidateShaderBinding(); + } } /*! @@ -705,6 +726,11 @@ namespace Nz m_pipelineUpdated = false; } + inline void Material::InvalidateShaderBinding() + { + //TODO + } + inline void Material::UpdatePipeline() const { for (auto& shader : m_pipelineInfo.shaders) diff --git a/src/Nazara/Graphics/BasicMaterial.cpp b/src/Nazara/Graphics/BasicMaterial.cpp index f92e61f7f..089438336 100644 --- a/src/Nazara/Graphics/BasicMaterial.cpp +++ b/src/Nazara/Graphics/BasicMaterial.cpp @@ -60,17 +60,18 @@ namespace Nz { NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_uniformBlockIndex), BufferAccess_ReadOnly); - return AccessByOffset(mapper.GetPointer(), m_uniformOffsets.alphaThreshold); + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); + + return AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold); } Color BasicMaterial::GetDiffuseColor() const { NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_uniformBlockIndex), BufferAccess_ReadOnly); + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); - const float* colorPtr = AccessByOffset(mapper.GetPointer(), m_uniformOffsets.diffuseColor); + const float* colorPtr = AccessByOffset(bufferData.data(), m_uniformOffsets.diffuseColor); return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float } @@ -78,16 +79,17 @@ namespace Nz { NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_uniformBlockIndex), BufferAccess_WriteOnly); - AccessByOffset(mapper.GetPointer(), m_uniformOffsets.alphaThreshold) = alphaThreshold; + std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); + AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold) = alphaThreshold; } void BasicMaterial::SetDiffuseColor(const Color& diffuse) { NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_uniformBlockIndex), BufferAccess_WriteOnly); - float* colorPtr = AccessByOffset(mapper.GetPointer(), m_uniformOffsets.diffuseColor); + std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); + + float* colorPtr = AccessByOffset(bufferData.data(), m_uniformOffsets.diffuseColor); colorPtr[0] = diffuse.r / 255.f; colorPtr[1] = diffuse.g / 255.f; colorPtr[2] = diffuse.b / 255.f; diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp index 7a51c9ba2..4f12980b7 100644 --- a/src/Nazara/Graphics/Material.cpp +++ b/src/Nazara/Graphics/Material.cpp @@ -39,11 +39,53 @@ namespace Nz m_uniformBuffers.reserve(m_settings->GetUniformBlocks().size()); for (const auto& uniformBufferInfo : m_settings->GetUniformBlocks()) { - //TODO: Use pools - UniformBufferRef ubo = UniformBuffer::New(static_cast(uniformBufferInfo.blockSize), DataStorage_Hardware, BufferUsage_Dynamic); - ubo->Fill(uniformBufferInfo.defaultValues.data(), 0, uniformBufferInfo.defaultValues.size()); + auto& uniformBuffer = m_uniformBuffers.emplace_back(); - m_uniformBuffers.emplace_back(std::move(ubo)); + uniformBuffer.buffer = Graphics::Instance()->GetRenderDevice().InstantiateBuffer(Nz::BufferType_Uniform); + if (!uniformBuffer.buffer->Initialize(uniformBufferInfo.blockSize, BufferUsage_Dynamic)) + throw std::runtime_error("failed to initialize UBO memory"); + + assert(uniformBufferInfo.defaultValues.size() <= uniformBufferInfo.blockSize); + + uniformBuffer.buffer->Fill(uniformBufferInfo.defaultValues.data(), 0, uniformBufferInfo.defaultValues.size()); + uniformBuffer.data.resize(uniformBufferInfo.blockSize); + std::memcpy(uniformBuffer.data.data(), uniformBufferInfo.defaultValues.data(), uniformBufferInfo.defaultValues.size()); } } + + void Material::UpdateShaderBinding(ShaderBinding& shaderBinding) const + { + // TODO: Use StackVector + std::vector bindings; + + + std::size_t bindingIndex = 0; + + for (const auto& textureSlot : m_textures) + { + if (textureSlot.texture && textureSlot.sampler) + { + bindings.push_back({ + bindingIndex, + ShaderBinding::TextureBinding { + textureSlot.texture.get(), textureSlot.sampler.get() + } + }); + } + + bindingIndex++; + } + + for (const auto& ubo : m_uniformBuffers) + { + bindings.push_back({ + bindingIndex++, + ShaderBinding::UniformBufferBinding { + ubo.buffer.get(), 0, ubo.buffer->GetSize() + } + }); + } + + shaderBinding.Update(bindings.data(), bindings.size()); + } } diff --git a/src/Nazara/Graphics/PhongLightingMaterial.cpp b/src/Nazara/Graphics/PhongLightingMaterial.cpp index d8258c55a..c6d8f4297 100644 --- a/src/Nazara/Graphics/PhongLightingMaterial.cpp +++ b/src/Nazara/Graphics/PhongLightingMaterial.cpp @@ -49,17 +49,17 @@ namespace Nz { NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly); - return AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.alphaThreshold); + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + return AccessByOffset(bufferData.data(), m_phongUniformOffsets.alphaThreshold); } Color PhongLightingMaterial::GetAmbientColor() const { NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly); + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); - const float* colorPtr = AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.ambientColor); + const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.ambientColor); return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float } @@ -67,9 +67,9 @@ namespace Nz { NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly); + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); - const float* colorPtr = AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.diffuseColor); + const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.diffuseColor); return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float } @@ -77,17 +77,17 @@ namespace Nz { NazaraAssert(HasShininess(), "Material has no shininess uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly); - return AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.shininess); + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + return AccessByOffset(bufferData.data(), m_phongUniformOffsets.shininess); } Color PhongLightingMaterial::GetSpecularColor() const { NazaraAssert(HasSpecularColor(), "Material has no specular color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly); + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); - const float* colorPtr = AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.specularColor); + const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.specularColor); return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float } @@ -95,16 +95,16 @@ namespace Nz { NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly); - AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.alphaThreshold) = alphaThreshold; + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + AccessByOffset(bufferData.data(), m_phongUniformOffsets.alphaThreshold) = alphaThreshold; } void PhongLightingMaterial::SetAmbientColor(const Color& ambient) { NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly); - float* colorPtr = AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.ambientColor); + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.ambientColor); colorPtr[0] = ambient.r / 255.f; colorPtr[1] = ambient.g / 255.f; colorPtr[2] = ambient.b / 255.f; @@ -115,8 +115,8 @@ namespace Nz { NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly); - float* colorPtr = AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.diffuseColor); + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.diffuseColor); colorPtr[0] = diffuse.r / 255.f; colorPtr[1] = diffuse.g / 255.f; colorPtr[2] = diffuse.b / 255.f; @@ -127,8 +127,8 @@ namespace Nz { NazaraAssert(HasSpecularColor(), "Material has no specular color uniform"); - BufferMapper mapper(m_material.GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly); - float* colorPtr = AccessByOffset(mapper.GetPointer(), m_phongUniformOffsets.specularColor); + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.specularColor); colorPtr[0] = diffuse.r / 255.f; colorPtr[1] = diffuse.g / 255.f; colorPtr[2] = diffuse.b / 255.f;