139 lines
6.1 KiB
C++
139 lines
6.1 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 openVulkanoCpp::Vulkan
|
|
{
|
|
static_assert(sizeof(vk::DescriptorSetLayoutBinding) == sizeof(DescriptorSetLayoutBinding));
|
|
|
|
VulkanShader::~VulkanShader()
|
|
{
|
|
if (!shader) return;
|
|
device.destroyPipeline(pipeline);
|
|
for(auto& shaderModule : shaderModules)
|
|
{
|
|
device.destroyShaderModule(shaderModule);
|
|
}
|
|
device.destroyPipelineLayout(pipelineLayout);
|
|
device.destroyDescriptorSetLayout(descriptorSetLayout);
|
|
}
|
|
|
|
void VulkanShader::Init(Context* context, Scene::Shader* shader, IShaderOwner* owner)
|
|
{
|
|
this->device = context->device->device;
|
|
this->shader = shader;
|
|
this->owner = owner;
|
|
this->context = context;
|
|
shader->renderShader = this;
|
|
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::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 = { {}, 1, 1, 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()
|
|
{
|
|
owner->RemoveShader(this);
|
|
}
|
|
|
|
void VulkanShader::CreatePipelineLayout()
|
|
{
|
|
vk::PushConstantRange camPushConstantDesc = { vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, 3 * sizeof(Math::Matrix4f) + sizeof(Math::Vector4f) + 8 * sizeof(float) };
|
|
std::array<vk::PushConstantRange, 1> camPushConstantDescs = { camPushConstantDesc };
|
|
std::array<vk::DescriptorSetLayoutBinding, 1> layoutBindings = { reinterpret_cast<const vk::DescriptorSetLayoutBinding&>(NODE_LAYOUT_BINDING) };
|
|
vk::DescriptorSetLayoutCreateInfo dslci = { {}, layoutBindings.size(), layoutBindings.data() };
|
|
descriptorSetLayout = device.createDescriptorSetLayout(dslci);
|
|
vk::PipelineLayoutCreateInfo plci = { {}, 1, &descriptorSetLayout, camPushConstantDescs.size(), camPushConstantDescs.data() };
|
|
pipelineLayout = this->device.createPipelineLayout(plci);
|
|
}
|
|
} |