Start refactoring shader system

This commit is contained in:
2021-01-14 16:01:11 +01:00
parent 43a41e5e58
commit eec33c30dc
4 changed files with 165 additions and 55 deletions

View File

@@ -50,7 +50,8 @@ public:
cam.Init(70, 16, 9, 0.1f, 100); cam.Init(70, 16, 9, 0.1f, 100);
scene.SetCamera(&cam); scene.SetCamera(&cam);
cam.SetMatrix(Utils::translate(Matrix4f(1), Vector3f_SIMD(0,0,-10))); 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); drawablesPool.resize(GEOS);
for(int i = 0; i < GEOS; i++) for(int i = 0; i < GEOS; i++)
{ {

View File

@@ -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 #pragma once
#include "Base/ICloseable.hpp" #include "Base/ICloseable.hpp"
#include "Base/Utils.hpp"
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
namespace openVulkanoCpp namespace openVulkanoCpp::Scene
{ {
namespace Scene enum class Topology : uint32_t
{ {
enum class Topology POINT_LIST = 0,
{ LINE_LIST,
PointList, LineList, LineStripe, TriangleList, TriangleStripe 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 public:
{ enum Type : uint32_t {
std::string vertexShaderName, fragmentShaderName; VERTEX = 1,
Topology topology = Topology::TriangleList; TESSELLATION_CONTROL = 2,
ICloseable* renderShader = nullptr; TESSELLATION_EVALUATION = 4,
GEOMETRY = 8,
FRAGMENT = 16,
COMPUTE = 32,
Shader() = default; // Mesh shader
~Shader() { if (renderShader) Shader::Close(); } MESH_TASK = 0x40,
MESH_MESH = 0x80,
void Init(const std::string& vertexShaderName, const std::string& fragmentShaderName) // Raytracing
{ RAY_GEN = 0x100,
if (renderShader) throw std::runtime_error("Shader already initialized!"); RAY_ANY_HIT = 0x200,
this->vertexShaderName = vertexShaderName; RAY_CLOSEST_HIT = 0x400,
this->fragmentShaderName = fragmentShaderName; RAY_MISS = 0x800,
} RAY_INTERSECTION = 0x1000,
RAY_CALLABLE = 0x2000,
void Close() override ALL_GRAPHICS = 0x0000001F
{
renderShader->Close();
renderShader = nullptr;
}
}; };
}
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<uint32_t>(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<ShaderProgram> 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<typename ...ARGS>
Shader& AddShaderProgram(ARGS&&... args)
{
if (renderShader) throw std::runtime_error("Shader already initialized!");
shaderPrograms.emplace_back(std::forward<ARGS>(args)...);
return *this;
}
void Close() override
{
renderShader->Close();
renderShader = nullptr;
}
};
} }

View File

@@ -12,40 +12,28 @@
namespace openVulkanoCpp::Vulkan 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) void VulkanShader::Init(Context* context, Scene::Shader* shader, IShaderOwner* owner)
{ {
this->device = context->device->device; this->device = context->device->device;
this->shader = shader; this->shader = shader;
this->owner = owner; this->owner = owner;
this->context = context; this->context = context;
shaderModuleVertex = context->device->CreateShaderModule(shader->vertexShaderName + ".vert.spv"); shaderModules.reserve(shader->shaderPrograms.size());
shaderModuleFragment = context->device->CreateShaderModule(shader->fragmentShaderName + ".frag.spv"); 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<vk::ShaderStageFlagBits>(static_cast<uint32_t>(shaderProgram.type)), shaderModule, "main"};
i++;
}
BuildPipeline(); BuildPipeline();
} }
void VulkanShader::BuildPipeline() void VulkanShader::BuildPipeline()
{ {
std::vector<vk::PipelineShaderStageCreateInfo> shaderStageCreateInfos(2); vk::VertexInputBindingDescription vertexBindDesc(0, sizeof(Vertex), vk::VertexInputRate::eVertex);
shaderStageCreateInfos[0] = { {}, vk::ShaderStageFlagBits::eVertex, shaderModuleVertex, "main" };
shaderStageCreateInfos[1] = { {}, vk::ShaderStageFlagBits::eFragment, shaderModuleFragment, "main" };
auto vertexBindDesc = vk::VertexInputBindingDescription(0, sizeof(Vertex), vk::VertexInputRate::eVertex);
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions; std::vector<vk::VertexInputAttributeDescription> attributeDescriptions;
attributeDescriptions.emplace_back(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position)); attributeDescriptions.emplace_back(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position));
attributeDescriptions.emplace_back(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, normal)); 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::PipelineViewportStateCreateInfo viewportStateCreateInfo = { {}, 1, &context->swapChain.GetFullscreenViewport(), 1, &context->swapChain.GetFullscreenScissor() };
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = { {}, 1, &vertexBindDesc, vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = { {}, 1, &vertexBindDesc,
static_cast<uint32_t>(attributeDescriptions.size()), attributeDescriptions.data() }; static_cast<uint32_t>(attributeDescriptions.size()), attributeDescriptions.data() };
vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, ToVkTopology(shader->topology), 0 }; vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, static_cast<vk::PrimitiveTopology>(shader->topology), 0 };
vk::PipelineRasterizationStateCreateInfo rasterizer = {}; vk::PipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.cullMode = vk::CullModeFlagBits::eBack; rasterizer.cullMode = vk::CullModeFlagBits::eBack;
vk::PipelineMultisampleStateCreateInfo msaa = {}; vk::PipelineMultisampleStateCreateInfo msaa = {};
@@ -71,7 +59,7 @@ namespace openVulkanoCpp::Vulkan
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast<uint32_t>(shaderStageCreateInfos.size()), shaderStageCreateInfos.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly, vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast<uint32_t>(shaderStageCreateInfo.size()), shaderStageCreateInfo.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly,
nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, context->pipeline.pipelineLayout, context->swapChainRenderPass.renderPass }; nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, context->pipeline.pipelineLayout, context->swapChainRenderPass.renderPass };
pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value; pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value;
} }
@@ -92,7 +80,9 @@ namespace openVulkanoCpp::Vulkan
owner->RemoveShader(this); owner->RemoveShader(this);
shader = nullptr; shader = nullptr;
device.destroyPipeline(pipeline); device.destroyPipeline(pipeline);
device.destroyShaderModule(shaderModuleVertex); for(auto& shaderModule : shaderModules)
device.destroyShaderModule(shaderModuleFragment); {
device.destroyShaderModule(shaderModule);
}
} }
} }

View File

@@ -9,6 +9,7 @@
#include "IRecordable.hpp" #include "IRecordable.hpp"
#include "Base/ICloseable.hpp" #include "Base/ICloseable.hpp"
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <vector>
namespace openVulkanoCpp namespace openVulkanoCpp
{ {
@@ -26,8 +27,9 @@ namespace openVulkanoCpp
{ {
Scene::Shader* shader = nullptr; Scene::Shader* shader = nullptr;
vk::Device device; vk::Device device;
vk::ShaderModule shaderModuleVertex, shaderModuleFragment; std::vector<vk::ShaderModule> shaderModules; // TODO manage live time somewhere else to allow sharing of shader programs
vk::Pipeline pipeline; std::vector<vk::PipelineShaderStageCreateInfo> shaderStageCreateInfo;
vk::Pipeline pipeline; // TODO pipeline and shader config should be split
IShaderOwner* owner; IShaderOwner* owner;
Context* context; Context* context;