#include "pipelines.h" #include #include bool vkutil::load_shader_module(const char *filePath, VkDevice device, VkShaderModule *outShaderModule) { std::ifstream file(filePath, std::ios::ate | std::ios::binary); if (!file.is_open()) { return false; } size_t fileSize = (size_t) file.tellg(); std::vector buffer(fileSize / sizeof(uint32_t)); file.seekg(0); file.read((char *) buffer.data(), fileSize); file.close(); VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.pNext = nullptr; createInfo.codeSize = buffer.size() * sizeof(uint32_t); createInfo.pCode = buffer.data(); VkShaderModule shaderModule; if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { return false; } *outShaderModule = shaderModule; return true; } void PipelineBuilder::clear() { _inputAssembly = {.sType=VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; _rasterizer = {.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; _colorBlendAttachment = {}; _multisampling = {.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; _pipelineLayout = {}; _depthStencil = {.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; _renderInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO}; _shaderStages.clear(); _colorAttachmentFormats.clear(); } VkPipeline PipelineBuilder::build_pipeline(VkDevice device) { VkPipelineViewportStateCreateInfo viewportState = {}; viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewportState.pNext = nullptr; viewportState.viewportCount = 1; viewportState.scissorCount = 1; VkPipelineColorBlendStateCreateInfo colorBlending = {}; colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlending.pNext = nullptr; colorBlending.logicOpEnable = VK_FALSE; colorBlending.logicOp = VK_LOGIC_OP_COPY; // For multiple color attachments (e.g., G-Buffer), we must provide one blend state per attachment. // Depth-only pipelines are allowed (0 color attachments). std::vector blendAttachments; uint32_t colorAttachmentCount = (uint32_t)_colorAttachmentFormats.size(); if (colorAttachmentCount > 0) { blendAttachments.assign(colorAttachmentCount, _colorBlendAttachment); colorBlending.attachmentCount = colorAttachmentCount; colorBlending.pAttachments = blendAttachments.data(); } else { colorBlending.attachmentCount = 0; colorBlending.pAttachments = nullptr; } VkPipelineVertexInputStateCreateInfo _vertexInputInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; VkGraphicsPipelineCreateInfo pipelineInfo = {.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; pipelineInfo.pNext = &_renderInfo; pipelineInfo.stageCount = (uint32_t) _shaderStages.size(); pipelineInfo.pStages = _shaderStages.data(); pipelineInfo.pVertexInputState = &_vertexInputInfo; pipelineInfo.pInputAssemblyState = &_inputAssembly; pipelineInfo.pViewportState = &viewportState; pipelineInfo.pRasterizationState = &_rasterizer; pipelineInfo.pMultisampleState = &_multisampling; pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDepthStencilState = &_depthStencil; pipelineInfo.layout = _pipelineLayout; VkDynamicState state[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; VkPipelineDynamicStateCreateInfo dynamicInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; dynamicInfo.pDynamicStates = &state[0]; dynamicInfo.dynamicStateCount = 2; pipelineInfo.pDynamicState = &dynamicInfo; VkPipeline newPipeline; if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &newPipeline) != VK_SUCCESS) { fmt::println("failed to create pipeline"); return VK_NULL_HANDLE; } else { return newPipeline; } } void PipelineBuilder::set_shaders(VkShaderModule vertexShader, VkShaderModule fragmentShader) { _shaderStages.clear(); _shaderStages.push_back( vkinit::pipeline_shader_stage_create_info(VK_SHADER_STAGE_VERTEX_BIT, vertexShader)); _shaderStages.push_back( vkinit::pipeline_shader_stage_create_info(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShader)); } void PipelineBuilder::set_input_topology(VkPrimitiveTopology topology) { _inputAssembly.topology = topology; _inputAssembly.primitiveRestartEnable = VK_FALSE; } void PipelineBuilder::set_polygon_mode(VkPolygonMode mode) { _rasterizer.polygonMode = mode; _rasterizer.lineWidth = 1.f; } void PipelineBuilder::set_cull_mode(VkCullModeFlags cullMode, VkFrontFace frontFace) { _rasterizer.cullMode = cullMode; _rasterizer.frontFace = frontFace; } void PipelineBuilder::set_multisampling_none() { _multisampling.sampleShadingEnable = VK_FALSE; _multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; _multisampling.minSampleShading = 1.0f; _multisampling.pSampleMask = nullptr; _multisampling.alphaToCoverageEnable = VK_FALSE; _multisampling.alphaToOneEnable = VK_FALSE; } void PipelineBuilder::disable_blending() { _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_FALSE; } void PipelineBuilder::enable_blending_additive() { _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; _colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; _colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; _colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; _colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; } void PipelineBuilder::enable_blending_alphablend() { _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; } void PipelineBuilder::set_color_attachment_format(VkFormat format) { _colorAttachmentFormats.clear(); _colorAttachmentFormats.push_back(format); _renderInfo.colorAttachmentCount = 1; _renderInfo.pColorAttachmentFormats = _colorAttachmentFormats.data(); } void PipelineBuilder::set_color_attachment_formats(std::span formats) { _colorAttachmentFormats.assign(formats.begin(), formats.end()); _renderInfo.colorAttachmentCount = (uint32_t)_colorAttachmentFormats.size(); _renderInfo.pColorAttachmentFormats = _colorAttachmentFormats.data(); } void PipelineBuilder::set_depth_format(VkFormat format) { _renderInfo.depthAttachmentFormat = format; } void PipelineBuilder::disable_depthtest() { _depthStencil.depthTestEnable = VK_FALSE; _depthStencil.depthWriteEnable = VK_FALSE; _depthStencil.depthCompareOp = VK_COMPARE_OP_NEVER; _depthStencil.depthBoundsTestEnable = VK_FALSE; _depthStencil.stencilTestEnable = VK_FALSE; _depthStencil.front = {}; _depthStencil.back = {}; _depthStencil.minDepthBounds = 0.f; _depthStencil.maxDepthBounds = 1.f; } void PipelineBuilder::enable_depthtest(bool depthWriteEnable, VkCompareOp op) { _depthStencil.depthTestEnable = VK_TRUE; _depthStencil.depthWriteEnable = depthWriteEnable; _depthStencil.depthCompareOp = op; _depthStencil.depthBoundsTestEnable = VK_FALSE; _depthStencil.stencilTestEnable = VK_FALSE; _depthStencil.front = {}; _depthStencil.back = {}; _depthStencil.minDepthBounds = 0.f; _depthStencil.maxDepthBounds = 1.f; }