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);
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++)
{

View File

@@ -1,32 +1,150 @@
/*
* 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 <string>
#include <stdexcept>
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
};
struct Shader : public virtual ICloseable
class ShaderProgramType
{
std::string vertexShaderName, fragmentShaderName;
Topology topology = Topology::TriangleList;
static constexpr std::string_view FILE_EXTENSIONS_OPENGL[] = {
".vert", ".tesc", ".tese", ".geom", ".frag", ".comp", ".mesh", ".task",
".rgen", ".rahit", ".rchit", ".rmiss", ".rint", ".rcall", ".glsl"
};
public:
enum Type : uint32_t {
VERTEX = 1,
TESSELLATION_CONTROL = 2,
TESSELLATION_EVALUATION = 4,
GEOMETRY = 8,
FRAGMENT = 16,
COMPUTE = 32,
// Mesh shader
MESH_TASK = 0x40,
MESH_MESH = 0x80,
// 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<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() { if (renderShader) Shader::Close(); }
~Shader() override { if (renderShader) Shader::Close(); }
void Init(const std::string& vertexShaderName, const std::string& fragmentShaderName)
Shader& AddShaderProgram(const ShaderProgram& shaderProgram)
{
if (renderShader) throw std::runtime_error("Shader already initialized!");
this->vertexShaderName = vertexShaderName;
this->fragmentShaderName = fragmentShaderName;
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
@@ -35,5 +153,4 @@ namespace openVulkanoCpp
renderShader = nullptr;
}
};
}
}

View File

@@ -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<vk::ShaderStageFlagBits>(static_cast<uint32_t>(shaderProgram.type)), shaderModule, "main"};
i++;
}
BuildPipeline();
}
void VulkanShader::BuildPipeline()
{
std::vector<vk::PipelineShaderStageCreateInfo> 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<vk::VertexInputAttributeDescription> 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<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 = {};
rasterizer.cullMode = vk::CullModeFlagBits::eBack;
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 };
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);
}
}
}

View File

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