#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) : 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 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(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(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 &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(bytecode.data()); VkShaderModule shaderModule; 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