147 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			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
							 |