From 93da8fc93405700fb95d0f2596fb116f4afc60fa Mon Sep 17 00:00:00 2001
From: Simeon Hermann <shermann04@uni-koblenz.de>
Date: Sun, 23 May 2021 22:23:53 +0200
Subject: [PATCH] [#9] implemented first steps for the creation managing of
 resource descriptions / descriptor sets

---
 config/Sources.cmake                 |  4 +-
 include/vkcv/Core.hpp                |  4 +-
 include/vkcv/DescriptorConfig.hpp    | 34 +++++++++++
 include/vkcv/DescriptorSet.hpp       | 19 +++++++
 include/vkcv/ResourcesConfig.hpp     | 23 --------
 projects/first_triangle/src/main.cpp | 26 +++++++++
 src/vkcv/Core.cpp                    |  5 +-
 src/vkcv/DescriptorManager.cpp       | 85 +++++++++++++++++++++++++++-
 src/vkcv/DescriptorManager.hpp       | 24 ++++++--
 src/vkcv/ResourcesConfig.cpp         |  0
 10 files changed, 189 insertions(+), 35 deletions(-)
 create mode 100644 include/vkcv/DescriptorConfig.hpp
 create mode 100644 include/vkcv/DescriptorSet.hpp
 delete mode 100644 include/vkcv/ResourcesConfig.hpp
 delete mode 100644 src/vkcv/ResourcesConfig.cpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index 7646cf6f..3d1120be 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -55,6 +55,6 @@ set(vkcv_sources
 		${vkcv_source}/vkcv/DescriptorManager.hpp
 		${vkcv_source}/vkcv/DescriptorManager.cpp
 
-		${vkcv_include}/vkcv/ResourcesConfig.hpp
-		${vkcv_source}/vkcv/ResourcesConfig.cpp
+		${vkcv_include}/vkcv/DescriptorConfig.hpp
+		${vkcv_source}/vkcv/DescriptorConfig.cpp
 )
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 79a9d29d..680f0b62 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -17,7 +17,7 @@
 #include "CommandResources.hpp"
 #include "SyncResources.hpp"
 #include "Result.hpp"
-#include "vkcv/ResourcesConfig.hpp"
+#include "vkcv/DescriptorConfig.hpp"
 
 namespace vkcv
 {
@@ -153,7 +153,7 @@ namespace vkcv
          *   @param setDescriptions
          *   @return
          */
-        ResourcesHandle createResourceDescription(const std::vector<SetDescription> &setDescriptions);
+        ResourcesHandle createResourceDescription(const std::vector<DescriptorSet> &descriptorSets);
 
 		/**
 		 * @brief start recording command buffers and increment frame index
diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp
new file mode 100644
index 00000000..c4666b18
--- /dev/null
+++ b/include/vkcv/DescriptorConfig.hpp
@@ -0,0 +1,34 @@
+#pragma once
+#include <vkcv/ShaderProgram.hpp>
+
+namespace vkcv
+{
+    enum class DescriptorType
+    {
+        // TODO:
+        //  uniform buffers, samplers, images should be supported for now!
+        UNIFORM_BUFFER,
+        SAMPLER,
+        IMAGE
+    };
+
+    struct DescriptorBinding
+    {
+        // TODO:
+        //  should contain something like the binding ID,
+        //  and the descriptor/resource type
+
+        uint32_t bindingID;
+        DescriptorType descriptorType;
+        uint32_t descriptorCount;
+        ShaderStage shaderStage;
+    };
+
+    struct DescriptorSet
+    {
+        // TODO:
+        //  should contain a collection of DescriptorBindings and the number of instances to be created from the set
+        std::vector<DescriptorBinding> bindings;
+        uint32_t setCount;
+    };
+}
diff --git a/include/vkcv/DescriptorSet.hpp b/include/vkcv/DescriptorSet.hpp
new file mode 100644
index 00000000..969f3558
--- /dev/null
+++ b/include/vkcv/DescriptorSet.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <vulkan/vulkan.hpp>
+
+namespace vkcv {
+
+	class DescriptorSet
+	{
+
+	public:
+		DescriptorSet::DescriptorSet();
+		void createDescriptorSets(vk::Device device);
+	private:
+		//std::vector<vk::DescriptorPoolSize> descriptorPoolSizes;
+		//std::vector<vk::DescriptorSetLayoutBinding> descriptorSetLayoutBinding;
+		//vk::DescriptorSetLayout descriptorSetLayout;
+		//vk::DescriptorPool descriptorPool;
+	};
+}
\ No newline at end of file
diff --git a/include/vkcv/ResourcesConfig.hpp b/include/vkcv/ResourcesConfig.hpp
deleted file mode 100644
index d9e9a3f8..00000000
--- a/include/vkcv/ResourcesConfig.hpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-namespace vkcv
-{
-    enum class ResourceType
-    {
-        // TODO:
-        //  uniform buffers, samplers, images should be supported for now!
-    };
-
-    struct BindingDescription
-    {
-        // TODO:
-        //  should contain something like the binding ID,
-        //  and the descriptor/resource type
-    };
-
-    struct SetDescription
-    {
-        // TODO:
-        //  should contain a collection of BindingDescriptions
-    };
-}
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 3c3f91de..ae0f4f8a 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -2,6 +2,7 @@
 #include <vkcv/Core.hpp>
 #include <vkcv/Window.hpp>
 #include <vkcv/ShaderProgram.hpp>
+#include <vkcv/DescriptorConfig.hpp>
 
 int main(int argc, const char** argv) {
     const char* applicationName = "First Triangle";
@@ -81,6 +82,31 @@ int main(int argc, const char** argv) {
 		return EXIT_FAILURE;
 	}
 
+//---------CREATION OF RESOURCES/DESCRIPTORS------------------
+	//just an example
+	//creates 3 descriptor sets with one descriptor each
+	std::vector<vkcv::DescriptorSet> sets;
+	vkcv::DescriptorType typeA = vkcv::DescriptorType::UNIFORM_BUFFER;
+	vkcv::DescriptorType typeB = vkcv::DescriptorType::IMAGE;
+	vkcv::DescriptorType typeC = vkcv::DescriptorType::SAMPLER;
+	std::vector<vkcv::DescriptorType> types = { typeA, typeB, typeC };
+	for (int i = 0; i < types.size(); i++)
+	{
+		vkcv::DescriptorBinding bind{};
+		bind.bindingID = i;
+		bind.descriptorType = types[i];
+		bind.descriptorCount = 1;
+		bind.shaderStage = vkcv::ShaderStage::VERTEX;
+
+		vkcv::DescriptorSet set{};
+		std::vector<vkcv::DescriptorBinding> bindings = { bind };
+		set.bindings = bindings;
+		set.setCount = 1;
+
+		sets.push_back(set);
+	}
+	core.createResourceDescription(sets);
+
 	/*
 	 * BufferHandle triangleVertices = core.createBuffer(vertices);
 	 * BufferHandle triangleIndices = core.createBuffer(indices);
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index cbf5474b..2b544efe 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -215,11 +215,12 @@ namespace vkcv
 		return m_swapchain.getSurfaceFormat().format;
 	}
 
-    ResourcesHandle Core::createResourceDescription(const std::vector<SetDescription> &setDescriptions)
+    ResourcesHandle Core::createResourceDescription(const std::vector<DescriptorSet> &descriptorSets)
     {
         // TODO:
         //  call DescriptorManager's createResourceDescription
         //  let it do the actual work! No vulkan stuff here.
-        return ResourcesHandle{0};
+		DescriptorManager descriptorManager = DescriptorManager(m_Context.getDevice());
+        return descriptorManager.createResourceDescription(descriptorSets);
     }
 }
diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp
index 32e0d031..b19c2e54 100644
--- a/src/vkcv/DescriptorManager.cpp
+++ b/src/vkcv/DescriptorManager.cpp
@@ -1,14 +1,95 @@
 #include "DescriptorManager.hpp"
+#include <vkcv/ShaderProgram.hpp>
 
 
 namespace vkcv
 {
-    ResourcesHandle vkcv::DescriptorManager::createResourceDescription(const std::vector<SetDescription> &setDescriptions)
+
+    DescriptorManager::DescriptorManager(vk::Device device) noexcept:
+        m_Device{ device }, m_NextDescriptorSetID{ 1 }
+    {
+        m_DescriptorTypes = { DescriptorType::UNIFORM_BUFFER, DescriptorType::SAMPLER, DescriptorType::IMAGE };
+        uint32_t sizesPerType = 1000;
+        uint32_t maxSetsPerPool = 1000;
+
+        std::vector<vk::DescriptorPoolSize> descriptorPoolSizes;
+        for (int i = 0; i < m_DescriptorTypes.size(); i++) {
+            vk::DescriptorType type = convertDescriptorTypeFlag(m_DescriptorTypes[i]);
+            vk::DescriptorPoolSize poolSize(type, sizesPerType);
+            descriptorPoolSizes.push_back(poolSize);
+        }
+        vk::DescriptorPoolCreateInfo poolInfo({}, maxSetsPerPool, descriptorPoolSizes);
+        m_Pool = m_Device.createDescriptorPool(poolInfo, nullptr);
+    }
+
+    ResourcesHandle DescriptorManager::createResourceDescription(const std::vector<DescriptorSet> &p_descriptorSets) 
     {
         // TODO: create all vk::DescriptorSets and allocate them from the pool
         // put them into a ResourceDescription struct
         // push that struct into m_Resources;
         // return the index into that object as ResourcesHandle;
-        return ResourcesHandle{0};
+
+        ResourceDescription resource{};
+
+        for (int i = 0; i < p_descriptorSets.size(); i++) {
+            DescriptorSet set = p_descriptorSets[i];
+            std::vector<vk::DescriptorSetLayoutBinding> setBindings;
+            for (int j = 0; j < set.bindings.size(); j++) {
+                //creates each binding of the set
+                DescriptorBinding binding = set.bindings[j];
+                vk::DescriptorType type = convertDescriptorTypeFlag(binding.descriptorType);
+                vk::ShaderStageFlagBits stage = convertShaderStageFlag(binding.shaderStage);
+                vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding(binding.bindingID, type, binding.descriptorCount, stage);
+                setBindings.push_back(descriptorSetLayoutBinding);
+            }
+            //creates the descriptor set layouts
+            vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutInfo({}, setBindings);
+            vk::DescriptorSetLayout allocLayout = m_Device.createDescriptorSetLayout(descriptorSetLayoutInfo, nullptr);
+            std::vector<vk::DescriptorSetLayout> allocLayouts(set.setCount, allocLayout);
+            //binds the layout to the pool
+            vk::DescriptorSetAllocateInfo allocInfo(m_Pool, allocLayout);
+
+            //creates and allocates the set(s) based on the layout
+            vk::DescriptorSet allocSet;
+            std::vector<vk::DescriptorSet> allocSets(set.setCount, allocSet);
+            m_Device.allocateDescriptorSets(&allocInfo, allocSets.data());
+
+            //inserts the descriptor sets and layouts into the resources (also considers copies of the same sets)
+            resource.descriptorSetLayouts.insert(resource.descriptorSetLayouts.begin(), allocLayouts.begin(), allocLayouts.end());
+            resource.descriptorSets.insert(resource.descriptorSets.end(), allocSets.begin(), allocSets.end());
+        }
+        m_Resources.push_back(resource);
+        return ResourcesHandle{m_NextDescriptorSetID++};
+    }
+
+    vk::DescriptorType vkcv::DescriptorManager::convertDescriptorTypeFlag(DescriptorType type) {
+        switch (type)
+        {
+        case vkcv::DescriptorType::UNIFORM_BUFFER:
+            return vk::DescriptorType::eUniformBuffer;
+        case vkcv::DescriptorType::SAMPLER:
+            return vk::DescriptorType::eSampler;
+        case vkcv::DescriptorType::IMAGE:
+            return vk::DescriptorType::eSampledImage;
+        }
     }
+
+    vk::ShaderStageFlagBits vkcv::DescriptorManager::convertShaderStageFlag(ShaderStage stage) {
+        switch (stage) 
+        {
+        case vkcv::ShaderStage::VERTEX:
+            return vk::ShaderStageFlagBits::eVertex;
+        case vkcv::ShaderStage::FRAGMENT:
+            return vk::ShaderStageFlagBits::eFragment;
+        case vkcv::ShaderStage::TESS_CONTROL:
+            return vk::ShaderStageFlagBits::eTessellationControl;
+        case vkcv::ShaderStage::TESS_EVAL:
+            return vk::ShaderStageFlagBits::eTessellationControl;
+        case vkcv::ShaderStage::GEOMETRY:
+            return vk::ShaderStageFlagBits::eGeometry;
+        case vkcv::ShaderStage::COMPUTE:
+            return vk::ShaderStageFlagBits::eCompute;
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/src/vkcv/DescriptorManager.hpp b/src/vkcv/DescriptorManager.hpp
index 5a9d4feb..d906c73a 100644
--- a/src/vkcv/DescriptorManager.hpp
+++ b/src/vkcv/DescriptorManager.hpp
@@ -1,24 +1,26 @@
 #include <vulkan/vulkan.hpp>
 
 #include "vkcv/Handles.hpp"
-#include "vkcv/ResourcesConfig.hpp"
+#include "vkcv/DescriptorConfig.hpp"
 
 namespace vkcv
 {
 	class DescriptorManager
 	{
 	public:
-	    explicit DescriptorManager(vk::Device) noexcept;
-	    ~DescriptorManager();
+	    explicit DescriptorManager(vk::Device device) noexcept;
+	    ~DescriptorManager() = default;
 
 
 	    // TODO: Interface
 	    //  user wishes to create descriptor sets {X,Y,Z} each with different descriptions {A,B,C}
 	    //  returns a resource
-        ResourcesHandle createResourceDescription(const std::vector<SetDescription> &setDescriptions);
+        ResourcesHandle createResourceDescription(const std::vector<DescriptorSet> & p_descriptorSets);
 
 	private:
+		vk::Device m_Device;
         vk::DescriptorPool m_Pool;
+		uint64_t m_NextDescriptorSetID;
 
         // TODO: container for all resources requested by the user
         struct ResourceDescription
@@ -28,5 +30,19 @@ namespace vkcv
         };
 
         std::vector<ResourceDescription> m_Resources;
+		std::vector<DescriptorType> m_DescriptorTypes;
+		
+		/**
+		* converts the flags of the descriptor types from VulkanCV (vkcv) to Vulkan (vk)
+		* @param[in] vkcv flag of the DescriptorType (see DescriptorConfig.hpp)
+		* @return vk flag of the DescriptorType
+		*/
+		vk::DescriptorType convertDescriptorTypeFlag(DescriptorType type);
+		/**
+		* converts the flags of the shader stages from VulkanCV (vkcv) to Vulkan (vk)
+		* @param[in] vkcv flag of the ShaderStage (see ShaderProgram.hpp)
+		* @return vk flag of the ShaderStage
+		*/
+		vk::ShaderStageFlagBits vkcv::DescriptorManager::convertShaderStageFlag(ShaderStage stage);
 	};
 }
\ No newline at end of file
diff --git a/src/vkcv/ResourcesConfig.cpp b/src/vkcv/ResourcesConfig.cpp
deleted file mode 100644
index e69de29b..00000000
-- 
GitLab