Start refactoring shader system
This commit is contained in:
@@ -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++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user