From aad45984b1f9f2383bda074a4d35fe1160c6ef03 Mon Sep 17 00:00:00 2001
From: Leonie Franken <lfranken@uni-koblenz.de>
Date: Fri, 28 May 2021 13:14:17 +0200
Subject: [PATCH] [#36] vertex layout reflection done

---
 config/Sources.cmake           |  3 ++
 include/vkcv/ShaderProgram.hpp |  6 ++-
 include/vkcv/VertexLayout.hpp  | 37 ++++++++++++++++
 src/vkcv/ShaderProgram.cpp     | 78 +++++++++++++++++++++++++++-------
 src/vkcv/VertexLayout.cpp      | 53 +++++++++++++++++++++++
 5 files changed, 161 insertions(+), 16 deletions(-)
 create mode 100644 include/vkcv/VertexLayout.hpp
 create mode 100644 src/vkcv/VertexLayout.cpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index 0d0a3787..63178767 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -51,4 +51,7 @@ set(vkcv_sources
         
         ${vkcv_source}/vkcv/Framebuffer.hpp
         ${vkcv_source}/vkcv/Framebuffer.cpp
+
+		${vkcv_include}/vkcv/VertexLayout.hpp
+		${vkcv_source}/vkcv/VertexLayout.cpp
 )
diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp
index 0a8470a9..af60f9fb 100644
--- a/include/vkcv/ShaderProgram.hpp
+++ b/include/vkcv/ShaderProgram.hpp
@@ -11,6 +11,7 @@
 #include <filesystem>
 #include <vulkan/vulkan.hpp>
 #include <spirv_cross.hpp>
+#include "vkcv/VertexLayout.hpp"
 
 namespace vkcv {
 
@@ -54,10 +55,13 @@ namespace vkcv {
 
         bool existsShader(ShaderStage shaderStage) const;
 
-        void reflectShader(ShaderStage shaderStage) const;
+        void reflectShader(ShaderStage shaderStage);
+
+        VertexLayout& getVertexLayout();
 
 	private:
         std::unordered_map<ShaderStage, Shader> m_Shaders;
 
+        VertexLayout m_VertexLayout;
 	};
 }
diff --git a/include/vkcv/VertexLayout.hpp b/include/vkcv/VertexLayout.hpp
new file mode 100644
index 00000000..f9579b5d
--- /dev/null
+++ b/include/vkcv/VertexLayout.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <unordered_map>
+#include <vector>
+#include <iostream>
+
+namespace vkcv{
+    enum class VertexFormat{
+        FLOAT,
+        FLOAT2,
+        FLOAT3,
+        FLOAT4,
+        INT,
+        INT2,
+        INT3,
+        INT4
+    };
+
+    struct VertexInputAttachment{
+        VertexInputAttachment() = delete;
+        VertexInputAttachment(uint32_t location, uint32_t binding, VertexFormat format, uint32_t offset) noexcept;
+
+        uint32_t location;
+        uint32_t binding;
+        VertexFormat format;
+        uint32_t offset;
+    };
+
+    struct VertexLayout{
+        VertexLayout() noexcept;
+        VertexLayout(const std::vector<VertexInputAttachment> &inputs) noexcept;
+        std::unordered_map<uint32_t, VertexInputAttachment> attachmentMap;
+        uint32_t stride;
+    };
+
+
+}
\ No newline at end of file
diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp
index fce6ea35..69ad7c31 100644
--- a/src/vkcv/ShaderProgram.cpp
+++ b/src/vkcv/ShaderProgram.cpp
@@ -27,8 +27,46 @@ namespace vkcv {
         return buffer;
 	}
 
+	VertexFormat convertFormat(spirv_cross::SPIRType::BaseType basetype, uint32_t vecsize){
+        switch (basetype) {
+            case spirv_cross::SPIRType::Int:
+                switch (vecsize) {
+                    case 1:
+                        return VertexFormat::INT;
+                    case 2:
+                        return VertexFormat::INT2;
+                    case 3:
+                        return VertexFormat::INT3;
+                    case 4:
+                        return VertexFormat::INT4;
+                    default:
+                        break;
+                }
+                break;
+            case spirv_cross::SPIRType::Float:
+                switch (vecsize) {
+                    case 1:
+                        return VertexFormat::FLOAT;
+                    case 2:
+                        return VertexFormat::FLOAT2;
+                    case 3:
+                        return VertexFormat::FLOAT3;
+                    case 4:
+                        return VertexFormat::FLOAT4;
+                    default:
+                        break;
+                }
+                break;
+            default:
+                break;
+        }
+        std::cout << "Shader Program Reflection: unknown Vertex Format" << std::endl;
+        return VertexFormat::FLOAT;
+	}
+
 	ShaderProgram::ShaderProgram() noexcept :
-	m_Shaders{}
+	m_Shaders{},
+    m_VertexLayout{}
 	{}
 
 	bool ShaderProgram::addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath)
@@ -60,27 +98,37 @@ namespace vkcv {
 	        return true;
     }
 
-    void ShaderProgram::reflectShader(ShaderStage shaderStage) const
+    void ShaderProgram::reflectShader(ShaderStage shaderStage)
     {
         auto shaderCodeChar = m_Shaders.at(shaderStage).shaderCode;
-        std::vector<uint32_t> shaderCode; //convert from char to uint 32. Is this the best way? Prob not.
+        std::vector<uint32_t> shaderCode;
 
-        for (uint32_t i = 0; i < shaderCodeChar.size(); i++) {
-            shaderCode.push_back((uint32_t) shaderCodeChar[i]);
+        for (uint32_t i = 0; i < shaderCodeChar.size()/4; i++) {
+            shaderCode.push_back(((uint32_t*) shaderCodeChar.data())[i]);
         }
 
-        //spirv_cross::Compiler comp(move(shaderCode));
-
-        /*
+        spirv_cross::Compiler comp(move(shaderCode));
         spirv_cross::ShaderResources resources = comp.get_shader_resources();
 
-        //testprint
-        for (auto &u : resources.uniform_buffers)
-        {
-            uint32_t set = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
-            uint32_t binding = comp.get_decoration(u.id, spv::DecorationBinding);
-            std::cout << 'Found UBO ' << &u << ' at set = ' << set << ', binding = ' << binding << std::endl;
+        std::vector<VertexInputAttachment> inputVec;
+        uint32_t offset = 0;
+
+        for (uint32_t i = 0; i < resources.stage_inputs.size() ; i++){
+            auto &u = resources.stage_inputs[i];
+            const spirv_cross::SPIRType &base_type = comp.get_type(u.base_type_id);
+
+            VertexInputAttachment input = VertexInputAttachment(comp.get_decoration(u.id,spv::DecorationLocation),
+                                                                0,
+                                                                convertFormat(base_type.basetype, base_type.vecsize),
+                                                                offset);
+            inputVec.push_back(input);
+            offset += base_type.vecsize * base_type.width/8;
         }
-         */
+
+        m_VertexLayout = VertexLayout(inputVec);
     }
+
+    VertexLayout& ShaderProgram::getVertexLayout(){
+        return m_VertexLayout;
+	}
 }
diff --git a/src/vkcv/VertexLayout.cpp b/src/vkcv/VertexLayout.cpp
new file mode 100644
index 00000000..88c9406b
--- /dev/null
+++ b/src/vkcv/VertexLayout.cpp
@@ -0,0 +1,53 @@
+//
+// Created by Charlotte on 28.05.2021.
+//
+
+#include "vkcv/VertexLayout.hpp"
+
+namespace vkcv {
+    uint32_t static getFormatSize(VertexFormat format) {
+        switch (format) {
+            case VertexFormat::FLOAT:
+                return 4;
+            case VertexFormat::FLOAT2:
+                return 8;
+            case VertexFormat::FLOAT3:
+                return 12;
+            case VertexFormat::FLOAT4:
+                return 16;
+            case VertexFormat::INT:
+                return 4;
+            case VertexFormat::INT2:
+                return 8;
+            case VertexFormat::INT3:
+                return 12;
+            case VertexFormat::INT4:
+                return 16;
+            default:
+                break;
+        }
+        std::cout << "VertexLayout: No format given" << std::endl;
+        return 0;
+    }
+
+    VertexInputAttachment::VertexInputAttachment(uint32_t location, uint32_t binding, VertexFormat format, uint32_t offset) noexcept:
+            location{location},
+            binding{binding},
+            format{format},
+            offset{offset}
+            {}
+
+    VertexLayout::VertexLayout() noexcept :
+    stride{0},
+    attachmentMap()
+    {}
+
+    VertexLayout::VertexLayout(const std::vector<VertexInputAttachment> &inputs) noexcept {
+        stride = 0;
+        for (const auto &input : inputs) {
+            attachmentMap.insert(std::make_pair(input.location, input));
+            stride += getFormatSize(input.format);
+        }
+    }
+
+}
\ No newline at end of file
-- 
GitLab