From eec33c30dc98e8f70499993a42b2c82dbf55ad7c Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Thu, 14 Jan 2021 16:01:11 +0100 Subject: [PATCH] Start refactoring shader system --- .../ExampleApps/CubesExampleApp.cpp | 3 +- openVulkanoCpp/Scene/Shader.hpp | 167 +++++++++++++++--- openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp | 44 ++--- openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp | 6 +- 4 files changed, 165 insertions(+), 55 deletions(-) diff --git a/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp b/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp index 356b1ad..54e77ac 100644 --- a/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp +++ b/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp @@ -50,7 +50,8 @@ public: cam.Init(70, 16, 9, 0.1f, 100); scene.SetCamera(&cam); cam.SetMatrix(Utils::translate(Matrix4f(1), Vector3f_SIMD(0,0,-10))); - shader.Init("Shader/basic", "Shader/basic"); + shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/basic"); + shader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/basic"); drawablesPool.resize(GEOS); for(int i = 0; i < GEOS; i++) { diff --git a/openVulkanoCpp/Scene/Shader.hpp b/openVulkanoCpp/Scene/Shader.hpp index d28069e..d28c9f8 100644 --- a/openVulkanoCpp/Scene/Shader.hpp +++ b/openVulkanoCpp/Scene/Shader.hpp @@ -1,39 +1,156 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + #pragma once #include "Base/ICloseable.hpp" +#include "Base/Utils.hpp" #include #include -namespace openVulkanoCpp +namespace openVulkanoCpp::Scene { - namespace Scene + enum class Topology : uint32_t { - enum class Topology - { - PointList, LineList, LineStripe, TriangleList, TriangleStripe + POINT_LIST = 0, + LINE_LIST, + LINE_STRIPE, + TRIANGLE_LIST, + TRIANGLE_STRIP, + TRIANGLE_FAN, + LINE_LIST_WITH_ADJACENCY, + LINE_STRIP_WITH_ADJACENCY, + TRIANGLE_LIST_WITH_ADJACENCY, + TRIANGLE_STRIP_WITH_ADJACENCY, + PATCH_LIST + }; + + class ShaderProgramType + { + static constexpr std::string_view FILE_EXTENSIONS_OPENGL[] = { + ".vert", ".tesc", ".tese", ".geom", ".frag", ".comp", ".mesh", ".task", + ".rgen", ".rahit", ".rchit", ".rmiss", ".rint", ".rcall", ".glsl" }; - - struct Shader : public virtual ICloseable - { - std::string vertexShaderName, fragmentShaderName; - Topology topology = Topology::TriangleList; - ICloseable* renderShader = nullptr; - Shader() = default; - ~Shader() { if (renderShader) Shader::Close(); } + public: + enum Type : uint32_t { + VERTEX = 1, + TESSELLATION_CONTROL = 2, + TESSELLATION_EVALUATION = 4, + GEOMETRY = 8, + FRAGMENT = 16, + COMPUTE = 32, - void Init(const std::string& vertexShaderName, const std::string& fragmentShaderName) - { - if (renderShader) throw std::runtime_error("Shader already initialized!"); - this->vertexShaderName = vertexShaderName; - this->fragmentShaderName = fragmentShaderName; - } + // Mesh shader + MESH_TASK = 0x40, + MESH_MESH = 0x80, - void Close() override - { - renderShader->Close(); - renderShader = nullptr; - } + // Raytracing + RAY_GEN = 0x100, + RAY_ANY_HIT = 0x200, + RAY_CLOSEST_HIT = 0x400, + RAY_MISS = 0x800, + RAY_INTERSECTION = 0x1000, + RAY_CALLABLE = 0x2000, + + ALL_GRAPHICS = 0x0000001F }; - } + + ShaderProgramType(Type type) : m_type(type) {} + + [[nodiscard]] constexpr std::string_view GetExtensionOpenGL() const + { + return FILE_EXTENSIONS_OPENGL[GetId()]; + } + + [[nodiscard]] constexpr uint32_t GetId() const + { + if (m_type == ALL_GRAPHICS) return 14; + return Utils::Log2OfPow2(static_cast(m_type)); + } + + [[nodiscard]] bool operator ==(Type rhs) const + { + return m_type == rhs; + } + + [[nodiscard]] bool operator !=(Type rhs) const + { + return m_type != rhs; + } + + [[nodiscard]] operator uint32_t() const + { + return m_type; + } + + private: + Type m_type; + }; + + struct ShaderProgram + { + ShaderProgramType type; + std::string name; + + ShaderProgram(ShaderProgramType type, const std::string& name) : type(type), name(name) {} + + ShaderProgram(const ShaderProgram& program) : type(program.type), name(program.name) {} + + ShaderProgram(ShaderProgram&& program) : type(program.type), name(std::move(program.name)) {} + + [[nodiscard]] std::string GetShaderNameOpenGL() const + { + std::string oglName; + std::string_view ext = type.GetExtensionOpenGL(); + oglName.reserve(name.size() + ext.size()); + return oglName.append(name).append(ext); + } + + [[nodiscard]] std::string GetShaderNameVulkan() const + { + return GetShaderNameOpenGL() + ".spv"; + } + }; + + struct Shader final : public virtual ICloseable + { + std::vector shaderPrograms{}; + Topology topology = Topology::TRIANGLE_LIST; + ICloseable* renderShader = nullptr; + + Shader() = default; + ~Shader() override { if (renderShader) Shader::Close(); } + + Shader& AddShaderProgram(const ShaderProgram& shaderProgram) + { + if (renderShader) throw std::runtime_error("Shader already initialized!"); + shaderPrograms.push_back(shaderProgram); + return *this; + } + + Shader& AddShaderProgram(ShaderProgram&& shaderProgram) + { + if (renderShader) throw std::runtime_error("Shader already initialized!"); + shaderPrograms.push_back(std::move(shaderProgram)); + return *this; + } + + template + Shader& AddShaderProgram(ARGS&&... args) + { + if (renderShader) throw std::runtime_error("Shader already initialized!"); + shaderPrograms.emplace_back(std::forward(args)...); + return *this; + } + + void Close() override + { + renderShader->Close(); + renderShader = nullptr; + } + }; } diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp b/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp index b25dc85..7d76cfe 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp @@ -12,40 +12,28 @@ namespace openVulkanoCpp::Vulkan { - namespace - { - constexpr vk::PrimitiveTopology ToVkTopology(Scene::Topology topology) - { - switch (topology) - { - case Scene::Topology::PointList: return vk::PrimitiveTopology::ePointList; - case Scene::Topology::LineList: return vk::PrimitiveTopology::eLineList; - case Scene::Topology::LineStripe: return vk::PrimitiveTopology::eLineStrip; - case Scene::Topology::TriangleList: return vk::PrimitiveTopology::eTriangleList; - case Scene::Topology::TriangleStripe: return vk::PrimitiveTopology::eTriangleStrip; - default: throw std::runtime_error("Unknown topology!"); - } - } - } - void VulkanShader::Init(Context* context, Scene::Shader* shader, IShaderOwner* owner) { this->device = context->device->device; this->shader = shader; this->owner = owner; this->context = context; - shaderModuleVertex = context->device->CreateShaderModule(shader->vertexShaderName + ".vert.spv"); - shaderModuleFragment = context->device->CreateShaderModule(shader->fragmentShaderName + ".frag.spv"); + shaderModules.reserve(shader->shaderPrograms.size()); + shaderStageCreateInfo.resize(shader->shaderPrograms.size()); + int i = 0; + for(const auto& shaderProgram : shader->shaderPrograms) + { + const auto shaderModule = context->device->CreateShaderModule(shaderProgram.GetShaderNameVulkan()); + shaderModules.push_back(shaderModule); + shaderStageCreateInfo[i] = {{}, static_cast(static_cast(shaderProgram.type)), shaderModule, "main"}; + i++; + } BuildPipeline(); } void VulkanShader::BuildPipeline() { - std::vector shaderStageCreateInfos(2); - shaderStageCreateInfos[0] = { {}, vk::ShaderStageFlagBits::eVertex, shaderModuleVertex, "main" }; - shaderStageCreateInfos[1] = { {}, vk::ShaderStageFlagBits::eFragment, shaderModuleFragment, "main" }; - - auto vertexBindDesc = vk::VertexInputBindingDescription(0, sizeof(Vertex), vk::VertexInputRate::eVertex); + vk::VertexInputBindingDescription vertexBindDesc(0, sizeof(Vertex), vk::VertexInputRate::eVertex); std::vector attributeDescriptions; attributeDescriptions.emplace_back(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position)); attributeDescriptions.emplace_back(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, normal)); @@ -57,7 +45,7 @@ namespace openVulkanoCpp::Vulkan vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { {}, 1, &context->swapChain.GetFullscreenViewport(), 1, &context->swapChain.GetFullscreenScissor() }; vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = { {}, 1, &vertexBindDesc, static_cast(attributeDescriptions.size()), attributeDescriptions.data() }; - vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, ToVkTopology(shader->topology), 0 }; + vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, static_cast(shader->topology), 0 }; vk::PipelineRasterizationStateCreateInfo rasterizer = {}; rasterizer.cullMode = vk::CullModeFlagBits::eBack; vk::PipelineMultisampleStateCreateInfo msaa = {}; @@ -71,7 +59,7 @@ namespace openVulkanoCpp::Vulkan - vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast(shaderStageCreateInfos.size()), shaderStageCreateInfos.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly, + vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast(shaderStageCreateInfo.size()), shaderStageCreateInfo.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly, nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, context->pipeline.pipelineLayout, context->swapChainRenderPass.renderPass }; pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value; } @@ -92,7 +80,9 @@ namespace openVulkanoCpp::Vulkan owner->RemoveShader(this); shader = nullptr; device.destroyPipeline(pipeline); - device.destroyShaderModule(shaderModuleVertex); - device.destroyShaderModule(shaderModuleFragment); + for(auto& shaderModule : shaderModules) + { + device.destroyShaderModule(shaderModule); + } } } \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp index 6d0254c..715ab4b 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp @@ -9,6 +9,7 @@ #include "IRecordable.hpp" #include "Base/ICloseable.hpp" #include +#include namespace openVulkanoCpp { @@ -26,8 +27,9 @@ namespace openVulkanoCpp { Scene::Shader* shader = nullptr; vk::Device device; - vk::ShaderModule shaderModuleVertex, shaderModuleFragment; - vk::Pipeline pipeline; + std::vector shaderModules; // TODO manage live time somewhere else to allow sharing of shader programs + std::vector shaderStageCreateInfo; + vk::Pipeline pipeline; // TODO pipeline and shader config should be split IShaderOwner* owner; Context* context;