From 32157503e8f864662e55bbaf5bd971621ae1cb54 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 26 Apr 2020 18:21:38 +0200 Subject: [PATCH] OpenGL: Implement RenderPipelineLayout --- .../OpenGLRenderPipelineLayout.hpp | 44 ++++++--- .../OpenGLRenderPipelineLayout.inl | 12 +-- .../OpenGLRenderer/OpenGLShaderBinding.hpp | 6 +- .../OpenGLRenderer/OpenGLShaderBinding.inl | 8 +- .../Nazara/OpenGLRenderer/OpenGLTexture.hpp | 1 + .../Nazara/OpenGLRenderer/OpenGLTexture.inl | 4 + src/Nazara/OpenGLRenderer/OpenGLDevice.cpp | 3 +- .../OpenGLRenderPipelineLayout.cpp | 95 +++++++++---------- .../OpenGLRenderer/OpenGLShaderBinding.cpp | 73 +++++++------- 9 files changed, 127 insertions(+), 119 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp index 272a3fd22..2107d9379 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp @@ -12,11 +12,7 @@ #include #include #include -#include -#include -#include -#include -#include +#include #include #include #include @@ -28,39 +24,59 @@ namespace Nz friend OpenGLShaderBinding; public: - OpenGLRenderPipelineLayout() = default; + OpenGLRenderPipelineLayout(RenderPipelineLayoutInfo layoutInfo); + OpenGLRenderPipelineLayout(const OpenGLRenderPipelineLayout&) = delete; + OpenGLRenderPipelineLayout(OpenGLRenderPipelineLayout&&) = delete; ~OpenGLRenderPipelineLayout(); ShaderBindingPtr AllocateShaderBinding() override; - bool Create(Vk::Device& device, RenderPipelineLayoutInfo layoutInfo); + inline const RenderPipelineLayoutInfo& GetLayoutInfo() const; - inline Vk::Device* GetDevice() const; + inline std::size_t GetTextureDescriptorCount() const; + inline std::size_t GetUniformBufferDescriptorCount() const; - inline const Vk::DescriptorSetLayout& GetDescriptorSetLayout() const; - inline const Vk::PipelineLayout& GetPipelineLayout() const; + OpenGLRenderPipelineLayout& operator=(const OpenGLRenderPipelineLayout&) = delete; + OpenGLRenderPipelineLayout& operator=(OpenGLRenderPipelineLayout&&) = delete; private: struct DescriptorPool; + struct TextureDescriptor; + struct UniformBufferDescriptor; DescriptorPool& AllocatePool(); ShaderBindingPtr AllocateFromPool(std::size_t poolIndex); + TextureDescriptor& GetTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t textureIndex); + UniformBufferDescriptor& GetUniformBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t uniformBufferIndex); void Release(ShaderBinding& binding); inline void TryToShrink(); + struct TextureDescriptor + { + GLuint texture; + GLuint sampler; + }; + + struct UniformBufferDescriptor + { + GLuint buffer; + GLintptr offset; + GLsizeiptr size; + }; + struct DescriptorPool { using BindingStorage = std::aligned_storage_t; Bitset freeBindings; - Vk::DescriptorPool descriptorPool; + std::vector textureDescriptor; + std::vector uniformBufferDescriptor; std::unique_ptr storage; }; - MovablePtr m_device; + std::size_t m_textureDescriptorCount; + std::size_t m_uniformBufferDescriptorCount; std::vector m_descriptorPools; - Vk::DescriptorSetLayout m_descriptorSetLayout; - Vk::PipelineLayout m_pipelineLayout; RenderPipelineLayoutInfo m_layoutInfo; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.inl b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.inl index d4ca1e74d..a5646b1d9 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.inl @@ -7,19 +7,19 @@ namespace Nz { - inline Vk::Device* OpenGLRenderPipelineLayout::GetDevice() const + inline const RenderPipelineLayoutInfo& OpenGLRenderPipelineLayout::GetLayoutInfo() const { - return m_device.Get(); + return m_layoutInfo; } - inline const Vk::DescriptorSetLayout& OpenGLRenderPipelineLayout::GetDescriptorSetLayout() const + inline std::size_t OpenGLRenderPipelineLayout::GetTextureDescriptorCount() const { - return m_descriptorSetLayout; + return m_textureDescriptorCount; } - inline const Vk::PipelineLayout& OpenGLRenderPipelineLayout::GetPipelineLayout() const + inline std::size_t OpenGLRenderPipelineLayout::GetUniformBufferDescriptorCount() const { - return m_pipelineLayout; + return m_uniformBufferDescriptorCount; } inline void OpenGLRenderPipelineLayout::TryToShrink() diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp index 395570ddd..d920c2929 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp @@ -8,8 +8,8 @@ #define NAZARA_OPENGLRENDERER_OPENGLSHADERBINDING_HPP #include +#include #include -#include namespace Nz { @@ -18,13 +18,12 @@ namespace Nz class NAZARA_OPENGLRENDERER_API OpenGLShaderBinding : public ShaderBinding { public: - inline OpenGLShaderBinding(OpenGLRenderPipelineLayout& owner, std::size_t poolIndex, std::size_t bindingIndex, Vk::DescriptorSet descriptorSet); + inline OpenGLShaderBinding(OpenGLRenderPipelineLayout& owner, std::size_t poolIndex, std::size_t bindingIndex); OpenGLShaderBinding(const OpenGLShaderBinding&) = default; OpenGLShaderBinding(OpenGLShaderBinding&&) noexcept = default; ~OpenGLShaderBinding() = default; inline std::size_t GetBindingIndex() const; - inline const Vk::DescriptorSet& GetDescriptorSet() const; inline std::size_t GetPoolIndex() const; inline const OpenGLRenderPipelineLayout& GetOwner() const; @@ -36,7 +35,6 @@ namespace Nz private: void Release() override; - Vk::AutoDescriptorSet m_descriptorSet; OpenGLRenderPipelineLayout& m_owner; std::size_t m_bindingIndex; std::size_t m_poolIndex; diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.inl b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.inl index 8520a13b3..f823e2ffc 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.inl @@ -7,8 +7,7 @@ namespace Nz { - inline OpenGLShaderBinding::OpenGLShaderBinding(OpenGLRenderPipelineLayout& owner, std::size_t poolIndex, std::size_t bindingIndex, Vk::DescriptorSet descriptorSet) : - m_descriptorSet(std::move(descriptorSet)), + inline OpenGLShaderBinding::OpenGLShaderBinding(OpenGLRenderPipelineLayout& owner, std::size_t poolIndex, std::size_t bindingIndex) : m_owner(owner), m_bindingIndex(bindingIndex), m_poolIndex(poolIndex) @@ -25,11 +24,6 @@ namespace Nz return m_poolIndex; } - inline const Vk::DescriptorSet& OpenGLShaderBinding::GetDescriptorSet() const - { - return m_descriptorSet; - } - inline const OpenGLRenderPipelineLayout& OpenGLShaderBinding::GetOwner() const { return m_owner; diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp index d4552823c..47a60b42a 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp @@ -26,6 +26,7 @@ namespace Nz PixelFormat GetFormat() const override; UInt8 GetLevelCount() const override; Vector3ui GetSize(UInt8 level = 0) const override; + inline const GL::Texture& GetTexture() const; ImageType GetType() const override; bool Update(const void* ptr) override; diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl index 227f8c478..a9c2cfec4 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl @@ -7,6 +7,10 @@ namespace Nz { + inline const GL::Texture& OpenGLTexture::GetTexture() const + { + return m_texture; + } } #include diff --git a/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp b/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp index afe768ef3..19ebfd99c 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -58,7 +59,7 @@ namespace Nz std::shared_ptr OpenGLDevice::InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) { - return {}; + return std::make_shared(std::move(pipelineLayoutInfo)); } std::shared_ptr OpenGLDevice::InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.cpp index a0c8b8c05..4ab8d0c06 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.cpp @@ -2,8 +2,6 @@ // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#if 0 - #include #include #include @@ -15,6 +13,29 @@ namespace Nz { + OpenGLRenderPipelineLayout::OpenGLRenderPipelineLayout(RenderPipelineLayoutInfo layoutInfo) : + m_textureDescriptorCount(0), + m_uniformBufferDescriptorCount(0), + m_layoutInfo(std::move(layoutInfo)) + { + for (const auto& bindingInfo : m_layoutInfo.bindings) + { + switch (bindingInfo.type) + { + case ShaderBindingType::Texture: + m_textureDescriptorCount++; + break; + + case ShaderBindingType::UniformBuffer: + m_uniformBufferDescriptorCount++; + break; + + default: + throw std::runtime_error(("unknown binding type 0x" + String::Number(UnderlyingCast(bindingInfo.type), 16)).ToStdString()); + } + } + } + OpenGLRenderPipelineLayout::~OpenGLRenderPipelineLayout() { for (auto& pool : m_descriptorPools) @@ -46,50 +67,15 @@ namespace Nz return bindingPtr; } - bool OpenGLRenderPipelineLayout::Create(Vk::Device& device, RenderPipelineLayoutInfo layoutInfo) - { - m_device = &device; - m_layoutInfo = std::move(layoutInfo); - - StackVector layoutBindings = NazaraStackVector(VkDescriptorSetLayoutBinding, m_layoutInfo.bindings.size()); - - for (const auto& bindingInfo : m_layoutInfo.bindings) - { - VkDescriptorSetLayoutBinding& layoutBinding = layoutBindings.emplace_back(); - layoutBinding.binding = bindingInfo.index; - layoutBinding.descriptorCount = 1U; - layoutBinding.descriptorType = ToOpenGL(bindingInfo.type); - layoutBinding.stageFlags = ToOpenGL(bindingInfo.shaderStageFlags); - } - - if (!m_descriptorSetLayout.Create(*m_device, UInt32(layoutBindings.size()), layoutBindings.data())) - return false; - - if (!m_pipelineLayout.Create(*m_device, m_descriptorSetLayout)) - return false; - - return true; - } - auto OpenGLRenderPipelineLayout::AllocatePool() -> DescriptorPool& { - StackVector poolSizes = NazaraStackVector(VkDescriptorPoolSize, m_layoutInfo.bindings.size()); - constexpr UInt32 MaxSet = 128; - for (const auto& bindingInfo : m_layoutInfo.bindings) - { - VkDescriptorPoolSize& poolSize = poolSizes.emplace_back(); - poolSize.descriptorCount = MaxSet; - poolSize.type = ToOpenGL(bindingInfo.type); - } - DescriptorPool pool; - if (!pool.descriptorPool.Create(*m_device, MaxSet, UInt32(poolSizes.size()), poolSizes.data(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT)) - throw std::runtime_error("Failed to allocate new descriptor pool: " + TranslateOpenGLError(pool.descriptorPool.GetLastErrorCode())); - pool.freeBindings.Resize(MaxSet, true); pool.storage = std::make_unique(MaxSet); + pool.textureDescriptor.resize(m_textureDescriptorCount * MaxSet); + pool.uniformBufferDescriptor.resize(m_uniformBufferDescriptorCount * MaxSet); return m_descriptorPools.emplace_back(std::move(pool)); } @@ -102,17 +88,30 @@ namespace Nz if (freeBindingId == pool.freeBindings.npos) return {}; //< No free binding in this pool - Vk::DescriptorSet descriptorSet = pool.descriptorPool.AllocateDescriptorSet(m_descriptorSetLayout); - if (!descriptorSet) - { - NazaraWarning("Failed to allocate descriptor set: " + TranslateOpenGLError(pool.descriptorPool.GetLastErrorCode())); - return {}; - } - pool.freeBindings.Reset(freeBindingId); OpenGLShaderBinding* freeBindingMemory = reinterpret_cast(&pool.storage[freeBindingId]); - return ShaderBindingPtr(PlacementNew(freeBindingMemory, *this, poolIndex, freeBindingId, std::move(descriptorSet))); + return ShaderBindingPtr(PlacementNew(freeBindingMemory, *this, poolIndex, freeBindingId)); + } + + auto OpenGLRenderPipelineLayout::GetTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t textureIndex) -> TextureDescriptor& + { + assert(poolIndex < m_descriptorPools.size()); + auto& pool = m_descriptorPools[poolIndex]; + assert(!pool.freeBindings.Test(bindingIndex)); + assert(textureIndex < m_textureDescriptorCount); + + return pool.textureDescriptor[bindingIndex * m_textureDescriptorCount + textureIndex]; + } + + auto OpenGLRenderPipelineLayout::GetUniformBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t uniformBufferIndex) -> UniformBufferDescriptor& + { + assert(poolIndex < m_descriptorPools.size()); + auto& pool = m_descriptorPools[poolIndex]; + assert(!pool.freeBindings.Test(bindingIndex)); + assert(uniformBufferIndex < m_uniformBufferDescriptorCount); + + return pool.uniformBufferDescriptor[bindingIndex * m_uniformBufferDescriptorCount + uniformBufferIndex]; } void OpenGLRenderPipelineLayout::Release(ShaderBinding& binding) @@ -136,5 +135,3 @@ namespace Nz TryToShrink(); } } - -#endif diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp index 3a24e0fb1..8a36d9c97 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp @@ -2,8 +2,6 @@ // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#if 0 - #include #include #include @@ -17,57 +15,58 @@ namespace Nz { void OpenGLShaderBinding::Update(std::initializer_list bindings) { - StackVector bufferBinding = NazaraStackVector(VkDescriptorBufferInfo, bindings.size()); - StackVector imageBinding = NazaraStackVector(VkDescriptorImageInfo, bindings.size()); - StackVector writeOps = NazaraStackVector(VkWriteDescriptorSet, bindings.size()); + const auto& layoutInfo = m_owner.GetLayoutInfo(); for (const Binding& binding : bindings) { - VkWriteDescriptorSet& writeOp = writeOps.emplace_back(); - writeOp.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeOp.dstSet = m_descriptorSet; - writeOp.dstBinding = UInt32(binding.bindingIndex); + assert(binding.bindingIndex < layoutInfo.bindings.size()); + const auto& bindingDesc = layoutInfo.bindings[binding.bindingIndex]; - std::visit([&](auto&& arg) + std::size_t resourceIndex = 0; + for (std::size_t i = binding.bindingIndex; i > 0; --i) { - using T = std::decay_t; + // Use i-1 to prevent underflow in for loop + if (layoutInfo.bindings[i - 1].type == bindingDesc.type) + resourceIndex++; + } - if constexpr (std::is_same_v) + switch (bindingDesc.type) + { + case ShaderBindingType::Texture: { - OpenGLTexture& vkTexture = *static_cast(arg.texture); - OpenGLTextureSampler& vkSampler = *static_cast(arg.sampler); + if (!std::holds_alternative(binding.content)) + throw std::runtime_error("binding #" + std::to_string(binding.bindingIndex) + " is a texture but another binding type has been supplied"); - VkDescriptorImageInfo& imageInfo = imageBinding.emplace_back(); - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = vkTexture.GetImageView(); - imageInfo.sampler = vkSampler.GetSampler(); + const TextureBinding& texBinding = std::get(binding.content); - writeOp.descriptorCount = 1; - writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + OpenGLTexture& glTexture = *static_cast(texBinding.texture); + OpenGLTextureSampler& glSampler = *static_cast(texBinding.sampler); - writeOp.pImageInfo = &imageInfo; + auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, resourceIndex); + textureDescriptor.sampler = glSampler.GetSampler().GetObjectId(); + textureDescriptor.texture = glTexture.GetTexture().GetObjectId(); + break; } - else if constexpr (std::is_same_v) + + case ShaderBindingType::UniformBuffer: { - OpenGLBuffer& vkBuffer = *static_cast(arg.buffer); + if (!std::holds_alternative(binding.content)) + throw std::runtime_error("binding #" + std::to_string(binding.bindingIndex) + " is an uniform buffer but another binding type has been supplied"); - VkDescriptorBufferInfo& bufferInfo = bufferBinding.emplace_back(); - bufferInfo.buffer = vkBuffer.GetBuffer(); - bufferInfo.offset = arg.offset; - bufferInfo.range = arg.range; + const UniformBufferBinding& uboBinding = std::get(binding.content); - writeOp.descriptorCount = 1; - writeOp.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + OpenGLBuffer& glBuffer = *static_cast(uboBinding.buffer); + if (glBuffer.GetType() != BufferType_Uniform) + throw std::runtime_error("expected uniform buffer"); - writeOp.pBufferInfo = &bufferInfo; + auto& uboDescriptor = m_owner.GetUniformBufferDescriptor(m_poolIndex, m_bindingIndex, resourceIndex); + uboDescriptor.buffer = glBuffer.GetBuffer().GetObjectId(); + uboDescriptor.offset = uboBinding.offset; + uboDescriptor.size = uboBinding.range; + break; } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - - }, binding.content); + } } - - m_owner.GetDevice()->vkUpdateDescriptorSets(*m_owner.GetDevice(), UInt32(writeOps.size()), writeOps.data(), 0U, nullptr); } void OpenGLShaderBinding::Release() @@ -75,5 +74,3 @@ namespace Nz m_owner.Release(*this); } } - -#endif