zengine-old/test/vulkanTest/src/lve_pipeline.cpp
2024-02-18 21:33:25 +08:00

147 lines
5.4 KiB
C++

/*
* Little Vulkan Engine Pipeline class
*
* Copyright (C) 2020 by Blurrypiano - https://github.com/blurrypiano/littleVulkanEngine
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#include "lve_pipeline.hpp"
#include "lve_initializers.hpp"
// std
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <vector>
namespace lve {
LvePipeline::LvePipeline(std::string filePrefix, LveDevice& device, LveSwapChain& swapChain)
: device_{device}, filePrefix_{filePrefix}, swapChain_{swapChain} {
createGraphicsPipeline();
}
LvePipeline::~LvePipeline() {
vkDestroyPipeline(device_.device(), graphicsPipeline_, nullptr);
vkDestroyPipelineLayout(device_.device(), pipelineLayout_, nullptr);
}
void LvePipeline::bind(VkCommandBuffer commandBuffer) {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline_);
}
std::vector<char> LvePipeline::readFile(const std::string& filename) {
std::ifstream file(filename, std::ios::ate | std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("failed to open file!");
}
size_t fileSize = (size_t)file.tellg();
std::vector<char> buffer(fileSize);
file.seekg(0);
file.read(buffer.data(), fileSize);
file.close();
return buffer;
}
void LvePipeline::createGraphicsPipeline() {
auto vertCode = readFile(filePrefix_ + ".vert.spv");
auto fragCode = readFile(filePrefix_ + ".frag.spv");
VkShaderModule vertShaderModule = createShaderModule(vertCode);
VkShaderModule fragShaderModule = createShaderModule(fragCode);
auto vertShaderStageInfo =
initializers::shaderStage(vertShaderModule, VK_SHADER_STAGE_VERTEX_BIT);
auto fragShaderStageInfo =
initializers::shaderStage(fragShaderModule, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 0;
vertexInputInfo.pVertexBindingDescriptions = nullptr; // Optional
vertexInputInfo.vertexAttributeDescriptionCount = 0;
vertexInputInfo.pVertexAttributeDescriptions = nullptr; // Optional
auto inputAssembly = initializers::inputAssemblyState();
VkExtent2D swapChainExtent = swapChain_.getSwapChainExtent();
VkViewport viewport =
{0.0f, 0.0f, (float)swapChainExtent.width, (float)swapChainExtent.height, 0.0f, 1.0f};
VkRect2D scissor = {{0, 0}, swapChainExtent};
auto viewportState = initializers::viewportState(viewport, scissor);
auto rasterizer = initializers::rasterizationState();
auto multisampling = initializers::multisampleState();
auto colorBlendAttachment = initializers::colorBlendAttachmentState();
auto colorBlending = initializers::colorBlendingState(colorBlendAttachment);
auto depthStencil = initializers::depthStencilState();
// pipeline layout is used passing uniform information
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 0; // Optional
pipelineLayoutInfo.pSetLayouts = nullptr; // Optional
pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional
pipelineLayoutInfo.pPushConstantRanges = nullptr; // Optional
if (vkCreatePipelineLayout(device_.device(), &pipelineLayoutInfo, nullptr, &pipelineLayout_) !=
VK_SUCCESS) {
throw std::runtime_error("failed to create pipeline 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 = nullptr; // Optional
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr; // Optional
pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.layout = pipelineLayout_;
pipelineInfo.renderPass = swapChain_.getRenderPass();
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional
pipelineInfo.basePipelineIndex = -1; // Optional
if (vkCreateGraphicsPipelines(
device_.device(),
VK_NULL_HANDLE,
1,
&pipelineInfo,
nullptr,
&graphicsPipeline_) != VK_SUCCESS) {
throw std::runtime_error("failed to create graphics pipeline!");
}
vkDestroyShaderModule(device_.device(), fragShaderModule, nullptr);
vkDestroyShaderModule(device_.device(), vertShaderModule, nullptr);
}
VkShaderModule LvePipeline::createShaderModule(const std::vector<char>& code) {
VkShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
VkShaderModule shaderModule;
if (vkCreateShaderModule(device_.device(), &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
throw std::runtime_error("failed to create shader module!");
}
return shaderModule;
}
} // namespace lve