Files
OpenVulkano/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp
2024-07-22 14:19:09 +02:00

157 lines
7.0 KiB
C++

/*
* 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/.
*/
#include "VulkanShader.hpp"
#include "Vulkan/Context.hpp"
#include "Scene/Shader/Shader.hpp"
#include "Vulkan/Resources/IShaderOwner.hpp"
#include "Scene/Shader/DescriptorInputDescription.hpp"
namespace OpenVulkano::Vulkan
{
static_assert(sizeof(vk::DescriptorSetLayoutBinding) == sizeof(DescriptorSetLayoutBinding));
static_assert(sizeof(vk::PushConstantRange) == sizeof(PushConstantRange));
VulkanShader::~VulkanShader()
{
if (!shader) return;
Close();
}
void VulkanShader::Init(Context* context, Scene::Shader* shader, IShaderOwner* owner)
{
this->device = context->device->device;
this->shader = shader;
this->owner = owner;
this->context = context;
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();
shader->renderShader = this;
}
void VulkanShader::BuildPipeline()
{
std::vector<vk::VertexInputBindingDescription> vertexBindDesc;
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions;
vertexBindDesc.reserve(shader->vertexInputDescriptions.size());
for(const auto& description : shader->vertexInputDescriptions)
{
vertexBindDesc.emplace_back(description.bindingId, description.vertexSize, vk::VertexInputRate::eVertex);
if (shader->vertexInputDescriptions.size() > 1)
{
for(const auto& param : description.inputParameters)
{
attributeDescriptions.push_back(reinterpret_cast<const vk::VertexInputAttributeDescription&>(param));
}
}
}
uint32_t attributeDescriptionsSize;
vk::VertexInputAttributeDescription* attributeDescriptionsData;
if (shader->vertexInputDescriptions.size() == 1)
{ // Reuse already existing vertex attribute description
static_assert(sizeof(VertexInputParameter) == sizeof(vk::VertexInputAttributeDescription));
attributeDescriptionsSize = shader->vertexInputDescriptions[0].inputParameters.size();
attributeDescriptionsData = reinterpret_cast<vk::VertexInputAttributeDescription*>(shader->vertexInputDescriptions[0].inputParameters.data());
}
else
{
attributeDescriptionsSize = attributeDescriptions.size();
attributeDescriptionsData = attributeDescriptions.data();
}
vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { {}, 1, &context->swapChain.GetFullscreenViewport(), 1, &context->swapChain.GetFullscreenScissor() };
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = {
{}, static_cast<uint32_t>(vertexBindDesc.size()), vertexBindDesc.data(),
attributeDescriptionsSize, attributeDescriptionsData };
vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, static_cast<vk::PrimitiveTopology>(shader->topology), 0 };
vk::PipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.cullMode = static_cast<vk::CullModeFlagBits>(shader->cullMode);
vk::PipelineMultisampleStateCreateInfo msaa = {};
vk::PipelineDepthStencilStateCreateInfo depth = { {}, shader->depthTest, shader->depthWrite, vk::CompareOp::eLess };
depth.maxDepthBounds = 1;
vk::PipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eA | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eR;
if (shader->alphaBlend)
{
colorBlendAttachment.blendEnable = true;
colorBlendAttachment.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha;
colorBlendAttachment.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
colorBlendAttachment.colorBlendOp = vk::BlendOp::eAdd;
colorBlendAttachment.srcAlphaBlendFactor = vk::BlendFactor::eOne;
colorBlendAttachment.dstAlphaBlendFactor = vk::BlendFactor::eZero;
colorBlendAttachment.alphaBlendOp = vk::BlendOp::eAdd;
}
vk::PipelineColorBlendStateCreateInfo colorInfo = {};
colorInfo.attachmentCount = 1;
colorInfo.pAttachments = &colorBlendAttachment;
CreatePipelineLayout();
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast<uint32_t>(shaderStageCreateInfo.size()), shaderStageCreateInfo.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly,
nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, pipelineLayout, context->swapChainRenderPass.renderPass };
pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value;
}
void VulkanShader::Resize()
{
device.destroyPipeline(pipeline);
BuildPipeline();
}
void VulkanShader::Record(VulkanDrawContext* context)
{
context->commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
}
void VulkanShader::Close()
{
shader->renderShader = nullptr;
device.destroyPipeline(pipeline);
for(auto& shaderModule : shaderModules)
{
device.destroyShaderModule(shaderModule);
}
device.destroyPipelineLayout(pipelineLayout);
for(auto& descriptorSetLayout : descriptorSetLayouts)
device.destroyDescriptorSetLayout(descriptorSetLayout);
shader = nullptr;
if (owner) owner->RemoveShader(this);
}
void VulkanShader::CreatePipelineLayout()
{
if (!descriptorSetLayouts.empty())
{
for(auto& descriptorSetLayout : descriptorSetLayouts)
device.destroyDescriptorSetLayout(descriptorSetLayout);
descriptorSetLayouts.clear();
}
std::array<vk::DescriptorSetLayoutBinding, 1> layoutBindings1 = { reinterpret_cast<const vk::DescriptorSetLayoutBinding&>(Scene::Camera::DESCRIPTOR_SET_LAYOUT_BINDING) };
std::array<vk::DescriptorSetLayoutBinding, 1> layoutBindings2 = { reinterpret_cast<const vk::DescriptorSetLayoutBinding&>(Scene::Node::DESCRIPTOR_SET_LAYOUT_BINDING) };
descriptorSetLayouts.push_back(device.createDescriptorSetLayout({ {}, layoutBindings1.size(), layoutBindings1.data() }));
descriptorSetLayouts.push_back(device.createDescriptorSetLayout({ {}, layoutBindings2.size(), layoutBindings2.data() }));
for(const auto& set : shader->descriptorSets)
{
vk::DescriptorSetLayoutCreateInfo createInfo { {}, static_cast<uint32_t>(set.size()), reinterpret_cast<const vk::DescriptorSetLayoutBinding*>(set.data()) };
descriptorSetLayouts.push_back(device.createDescriptorSetLayout(createInfo));
}
vk::PushConstantRange* pcRanges = reinterpret_cast<vk::PushConstantRange*>(shader->pushConstantRanges.data());
vk::PipelineLayoutCreateInfo plci = {{}, static_cast<uint32_t>(descriptorSetLayouts.size()), descriptorSetLayouts.data(), static_cast<uint32_t>(shader->pushConstantRanges.size()), pcRanges };
pipelineLayout = this->device.createPipelineLayout(plci);
}
}