diff --git a/config/Sources.cmake b/config/Sources.cmake index 9a9f55747194ab9972254d5bf57ac11735607b06..27567beb5a09a5ba92698bcbf96d34193f56bb43 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -6,4 +6,6 @@ set(vkcv_sources ${vkcv_source}/vkcv/Window.cpp ${vkcv_source}/vkcv/CoreManager.hpp ${vkcv_source}/vkcv/CoreManager.cpp + ${vkcv_source}/vkcv/ShaderProgram.hpp + ${vkcv_source}/vkcv/ShaderProgram.cpp ) diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index cc592f468e0c3e95d64a1558404873c4ca19f8b9..6eadd66f03ad847a81555907082f91ca33fd3370 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -32,6 +32,10 @@ int main(int argc, const char** argv) { default: std::cout << "Unknown GPU vendor?! Either you're on an exotic system or your driver is broken..." << std::endl; } + vkcv::ShaderProgram shaderProgram = vkcv::ShaderProgram::create(context); + shaderProgram.addShader(VK_SHADER_STAGE_VERTEX_BIT, "../../../../../shaders/vert.spv"); + shaderProgram.addShader(VK_SHADER_STAGE_FRAGMENT_BIT, "../../../../../shaders/frag.spv"); + while (window.isWindowOpen()) { window.pollEvents(); } diff --git a/shaders/compile.bat b/shaders/compile.bat new file mode 100644 index 0000000000000000000000000000000000000000..6f8f661d4c2600edfee3bd90198fe32472dd4141 --- /dev/null +++ b/shaders/compile.bat @@ -0,0 +1,3 @@ +C:\VulkanSDK\1.2.170.0\Bin32\glslc.exe shader.vert -o vert.spv +C:\VulkanSDK\1.2.170.0\Bin32\glslc.exe shader.frag -o frag.spv +pause \ No newline at end of file diff --git a/shaders/frag.spv b/shaders/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..cb13e606fc0041e24ff6a63c0ec7dcca466732aa Binary files /dev/null and b/shaders/frag.spv differ diff --git a/shaders/shader.frag b/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..3363876e688e04c0941066b5549ae4fd9b3f507a --- /dev/null +++ b/shaders/shader.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/shaders/shader.vert b/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..9461e8f207aa283c258adcaff6359655fd62e9bb --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; + +layout(location = 0) out vec3 fragColor; + +void main() { + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; +} \ No newline at end of file diff --git a/shaders/vert.spv b/shaders/vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..4e979164bba0448a8d9b7f58356c924163bd6df4 Binary files /dev/null and b/shaders/vert.spv differ diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5bf995134d9a6af3002a92cbd158eb08862303f0 --- /dev/null +++ b/src/vkcv/ShaderProgram.cpp @@ -0,0 +1,104 @@ +/** + * @authors Simeon Hermann + * @file src/vkcv/ShaderProgram.cpp + * @brief ShaderProgram class to handle and prepare the shader stages for a graphics pipeline + */ + +#include "ShaderProgram.hpp" +#include <fstream> +#include <iostream> + + + +std::vector<const char*> validationLayers = { + "VK_LAYER_KHRONOS_validation" +}; + + +namespace vkcv { + + ShaderProgram::ShaderProgram(vkcv::Context& context) + : m_context(context) + {} + + std::vector<char> ShaderProgram::readFile(const std::string& filepath) { + std::ifstream file(filepath, std::ios::ate | std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("The file could not be opened."); + } + size_t fileSize = (size_t)file.tellg(); + std::vector<char> buffer(fileSize); + file.seekg(0); + file.read(buffer.data(), fileSize); + return buffer; + } + + VkShaderModule ShaderProgram::createShaderModule(const std::vector<char>& shaderCode) { + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = shaderCode.size(); + createInfo.pCode = reinterpret_cast<const uint32_t*>(shaderCode.data()); + + VkShaderModule shaderModule; + if (vkCreateShaderModule(m_context.getDevice(), &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { + throw std::runtime_error("Failed to create shader module!"); + } + return shaderModule; + } + + VkPipelineShaderStageCreateInfo ShaderProgram::createShaderStage(VkShaderModule& shaderModule, VkShaderStageFlagBits shaderStage) { + VkPipelineShaderStageCreateInfo shaderStageInfo{}; + shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageInfo.stage = shaderStage; + shaderStageInfo.module = shaderModule; + shaderStageInfo.pName = "main"; + return shaderStageInfo; + } + + ShaderProgram::~ShaderProgram() { + } + + ShaderProgram ShaderProgram::create(vkcv::Context& context) { + return ShaderProgram(context); + } + + void ShaderProgram::addShader(VkShaderStageFlagBits shaderStage, const std::string& filepath) { + if (containsShaderStage(shaderStage)) { + throw std::runtime_error("Shader program already contains this particular shader stage."); + } + else { + auto shaderCode = readFile(filepath); + VkShaderModule shaderModule = createShaderModule(shaderCode); + VkPipelineShaderStageCreateInfo shaderInfo = createShaderStage(shaderModule, shaderStage); + m_shaderStagesList.push_back(shaderInfo); + vkDestroyShaderModule(m_context.getDevice(), shaderModule, nullptr); + } + } + + bool ShaderProgram::containsShaderStage(VkShaderStageFlagBits shaderStage) { + for (int i = 0; i < m_shaderStagesList.size(); i++) { + if (m_shaderStagesList[i].stage == shaderStage) { + return true; + } + } + return false; + } + + bool ShaderProgram::deleteShaderStage(VkShaderStageFlagBits shaderStage) { + for (int i = 0; i < m_shaderStagesList.size() - 1; i++) { + if (m_shaderStagesList[i].stage == shaderStage) { + m_shaderStagesList.erase(m_shaderStagesList.begin() + i); + return true; + } + } + return false; + } + + std::vector<VkPipelineShaderStageCreateInfo> ShaderProgram::getShaderStages() { + return m_shaderStagesList; + } + + int ShaderProgram::getShaderStagesCount() { + return m_shaderStagesList.size(); + } +} diff --git a/src/vkcv/ShaderProgram.hpp b/src/vkcv/ShaderProgram.hpp new file mode 100644 index 0000000000000000000000000000000000000000..62c173bdaa542df90fd6664fe617dba9043ce036 --- /dev/null +++ b/src/vkcv/ShaderProgram.hpp @@ -0,0 +1,107 @@ +#pragma once +/** + * @authors Simeon Hermann + * @file src/vkcv/ShaderProgram.hpp + * @brief ShaderProgram class to handle and prepare the shader stages for a graphics pipeline + */ + +#define GLFW_INCLUDE_VULKAN +#include <vector> +#include <map> +#include <vulkan/vulkan.hpp> +#include "Context.hpp" + +namespace vkcv { + + class ShaderProgram final { + private: + + vkcv::Context& m_context; + std::vector<VkPipelineShaderStageCreateInfo> m_shaderStagesList; + /** + * Constructor of ShaderProgram requires a context for the logical device. + * @param context of the app + */ + ShaderProgram(vkcv::Context& context); + + /** + * Reads the file of a given shader code. + * Only used within the class. + * @param[in] relative path to the shader code + * @return vector of chars as a buffer for the code + */ + std::vector<char> readFile(const std::string& filepath); + + /** + * Creates a shader module that encapsulates the read shader code. + * Only used within the class. + * Shader modules are destroyed after respective shader stages are created. + * @param[in] a vector of chars as a buffer for the code + * @return shader module + */ + VkShaderModule createShaderModule(const std::vector<char>& shaderCode); + + /** + * Creates a shader stage (info struct) for the to be added shader. + * Only used within the class. + * @param[in] Shader module that encapsulates the shader code + * @param[in] flag that signals the respective shaderStage + * @return pipeline shader stage info struct + */ + VkPipelineShaderStageCreateInfo createShaderStage(VkShaderModule& shaderModule, VkShaderStageFlagBits shaderStage); + + + public: + + /** + * destructor of ShaderProgram, does nothing so far + */ + ~ShaderProgram(); + + /** + * Creates a shader program. + * So far it only calls the constructor. + * @param[in] context of the app + */ + static ShaderProgram create(vkcv::Context& context); + + /** + * Adds a shader into the shader program. + * The shader is only added if the shader program does not contain the particular shader stage already. + * Contains: (1) reading of the code, (2) creation of a shader module, (3) creation of a shader stage, (4) adding to the shader stage list, (5) destroying of the shader module + * @param[in] flag that signals the respective shaderStage (e.g. VK_SHADER_STAGE_VERTEX_BIT) + * @param[in] relative path to the shader code (e.g. "../../../../../shaders/vert.spv") + */ + void addShader(VkShaderStageFlagBits shaderStage, const std::string& filepath); + + /** + * Tests if the shader program contains a certain shader stage. + * @param[in] flag that signals the respective shader stage (e.g. VK_SHADER_STAGE_VERTEX_BIT) + * @return boolean that is true if the shader program contains the shader stage + */ + bool containsShaderStage(VkShaderStageFlagBits shaderStage); + + /** + * Deletes the given shader stage in the shader program. + * @param[in] flag that signals the respective shader stage (e.g. VK_SHADER_STAGE_VERTEX_BIT) + * @return boolean that is false if the shader stage was not found in the shader program + */ + bool deleteShaderStage(VkShaderStageFlagBits shaderStage); + + /** + * Returns a list with all the shader stages in the shader program. + * Needed for the transfer to the pipeline. + * @return vector list with all shader stage info structs + */ + std::vector<VkPipelineShaderStageCreateInfo> getShaderStages(); + + /** + * Returns the number of shader stages in the shader program. + * Needed for the transfer to the pipeline. + * @return integer with the number of stages + */ + int getShaderStagesCount(); + + + }; +}