mirror of
https://gitea.windcorp.ru/Wind-Corporation/Progressia.git
synced 2025-04-22 00:50:45 +03:00
222 lines
8.7 KiB
C++
222 lines
8.7 KiB
C++
#include "vulkan_pipeline.h"
|
|
|
|
#include "vulkan_adapter.h"
|
|
#include "vulkan_common.h"
|
|
#include "vulkan_descriptor_set.h"
|
|
#include "vulkan_render_pass.h"
|
|
|
|
namespace progressia::desktop {
|
|
|
|
Pipeline::Pipeline(Vulkan &vulkan) : layout(), vk(), vulkan(vulkan) {
|
|
|
|
auto &adapter = vulkan.getAdapter();
|
|
|
|
// Shaders
|
|
|
|
auto *vertShader = createShaderModule(adapter.loadVertexShader());
|
|
auto *fragShader = createShaderModule(adapter.loadFragmentShader());
|
|
|
|
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
|
|
vertShaderStageInfo.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
|
vertShaderStageInfo.module = vertShader;
|
|
vertShaderStageInfo.pName = "main";
|
|
|
|
VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
|
|
fragShaderStageInfo.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
fragShaderStageInfo.module = fragShader;
|
|
fragShaderStageInfo.pName = "main";
|
|
|
|
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo,
|
|
fragShaderStageInfo};
|
|
|
|
// Dynamic states
|
|
|
|
std::vector<VkDynamicState> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT,
|
|
VK_DYNAMIC_STATE_SCISSOR};
|
|
|
|
VkPipelineDynamicStateCreateInfo dynamicState{};
|
|
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
dynamicState.dynamicStateCount =
|
|
static_cast<uint32_t>(dynamicStates.size());
|
|
dynamicState.pDynamicStates = dynamicStates.data();
|
|
|
|
auto bindingDescription = adapter.getVertexInputBindingDescription();
|
|
auto attributeDescriptions = adapter.getVertexInputAttributeDescriptions();
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
|
|
vertexInputInfo.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
|
|
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
|
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
|
|
vertexInputInfo.vertexAttributeDescriptionCount =
|
|
static_cast<uint32_t>(attributeDescriptions.size());
|
|
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
|
|
|
|
// Input assembly
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
|
|
inputAssembly.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
|
|
|
// Viewport & scissor
|
|
|
|
VkPipelineViewportStateCreateInfo viewportState{};
|
|
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
viewportState.viewportCount = 1;
|
|
viewportState.scissorCount = 1;
|
|
|
|
// Rasterizer
|
|
|
|
VkPipelineRasterizationStateCreateInfo rasterizer{};
|
|
rasterizer.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
rasterizer.depthClampEnable = VK_FALSE;
|
|
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
|
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
|
rasterizer.lineWidth = 1.0F;
|
|
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
|
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
|
rasterizer.depthBiasEnable = VK_FALSE;
|
|
rasterizer.depthBiasConstantFactor = 0.0F; // Optional
|
|
rasterizer.depthBiasClamp = 0.0F; // Optional
|
|
rasterizer.depthBiasSlopeFactor = 0.0F; // Optional
|
|
|
|
// Multisampling (disabled)
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisampling{};
|
|
multisampling.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
multisampling.sampleShadingEnable = VK_FALSE;
|
|
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
multisampling.minSampleShading = 1.0F; // Optional
|
|
multisampling.pSampleMask = nullptr; // Optional
|
|
multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
|
|
multisampling.alphaToOneEnable = VK_FALSE; // Optional
|
|
|
|
// Depth testing
|
|
|
|
VkPipelineDepthStencilStateCreateInfo depthStencil{};
|
|
depthStencil.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
|
depthStencil.depthTestEnable = VK_TRUE;
|
|
depthStencil.depthWriteEnable = VK_TRUE;
|
|
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
|
|
depthStencil.depthBoundsTestEnable = VK_FALSE;
|
|
depthStencil.stencilTestEnable = VK_FALSE;
|
|
|
|
// Stencil testing (disabled)
|
|
|
|
// do nothing
|
|
|
|
// Color blending
|
|
|
|
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
|
|
colorBlendAttachment.colorWriteMask =
|
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
colorBlendAttachment.blendEnable = VK_TRUE;
|
|
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
colorBlendAttachment.dstColorBlendFactor =
|
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
|
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
|
|
VkPipelineColorBlendStateCreateInfo colorBlending{};
|
|
colorBlending.sType =
|
|
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
colorBlending.logicOpEnable = VK_FALSE;
|
|
colorBlending.logicOp = VK_LOGIC_OP_COPY; // Optional
|
|
colorBlending.attachmentCount = 1;
|
|
colorBlending.pAttachments = &colorBlendAttachment;
|
|
colorBlending.blendConstants[0] = 0.0F; // Optional
|
|
colorBlending.blendConstants[1] = 0.0F; // Optional
|
|
colorBlending.blendConstants[2] = 0.0F; // Optional
|
|
colorBlending.blendConstants[3] = 0.0F; // Optional
|
|
|
|
// Pipeline
|
|
|
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
|
|
auto layouts = vulkan.getAdapter().getUsedDSLayouts();
|
|
pipelineLayoutInfo.setLayoutCount = layouts.size();
|
|
pipelineLayoutInfo.pSetLayouts = layouts.data();
|
|
|
|
VkPushConstantRange pushConstantRange{};
|
|
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
|
pushConstantRange.offset = 0;
|
|
pushConstantRange.size = sizeof(glm::mat3x4);
|
|
|
|
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
|
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
|
|
|
|
vulkan.handleVkResult("Could not create PipelineLayout",
|
|
vkCreatePipelineLayout(vulkan.getDevice(),
|
|
&pipelineLayoutInfo, nullptr,
|
|
&layout));
|
|
|
|
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
pipelineInfo.stageCount = 2;
|
|
pipelineInfo.pStages = shaderStages;
|
|
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
|
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
|
pipelineInfo.pViewportState = &viewportState;
|
|
pipelineInfo.pRasterizationState = &rasterizer;
|
|
pipelineInfo.pMultisampleState = &multisampling;
|
|
pipelineInfo.pDepthStencilState = &depthStencil;
|
|
pipelineInfo.pColorBlendState = &colorBlending;
|
|
pipelineInfo.pDynamicState = &dynamicState;
|
|
pipelineInfo.layout = layout;
|
|
pipelineInfo.renderPass = vulkan.getRenderPass().getVk();
|
|
pipelineInfo.subpass = 0;
|
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional
|
|
pipelineInfo.basePipelineIndex = -1; // Optional
|
|
|
|
vulkan.handleVkResult(
|
|
"Could not create Pipeline",
|
|
vkCreateGraphicsPipelines(vulkan.getDevice(), VK_NULL_HANDLE, 1,
|
|
&pipelineInfo, nullptr, &vk));
|
|
|
|
// Cleanup
|
|
|
|
vkDestroyShaderModule(vulkan.getDevice(), fragShader, nullptr);
|
|
vkDestroyShaderModule(vulkan.getDevice(), vertShader, nullptr);
|
|
}
|
|
|
|
VkShaderModule Pipeline::createShaderModule(const std::vector<char> &bytecode) {
|
|
VkShaderModuleCreateInfo createInfo{};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
createInfo.codeSize = bytecode.size();
|
|
|
|
// Important - the buffer must be aligned properly. std::vector does that.
|
|
createInfo.pCode = reinterpret_cast<const uint32_t *>(bytecode.data());
|
|
|
|
VkShaderModule shaderModule = nullptr;
|
|
vulkan.handleVkResult("Could not load shader",
|
|
vkCreateShaderModule(vulkan.getDevice(), &createInfo,
|
|
nullptr, &shaderModule));
|
|
|
|
return shaderModule;
|
|
}
|
|
|
|
Pipeline::~Pipeline() {
|
|
vkDestroyPipeline(vulkan.getDevice(), vk, nullptr);
|
|
vkDestroyPipelineLayout(vulkan.getDevice(), layout, nullptr);
|
|
}
|
|
|
|
VkPipeline Pipeline::getVk() { return vk; }
|
|
|
|
VkPipelineLayout Pipeline::getLayout() { return layout; }
|
|
|
|
} // namespace progressia::desktop
|