/* Copyright (c) 2019-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 the "License"; * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "pipeline.h" #include "debug.h" #include "device.h" #include "pipeline_layout.h" #include "shader_module.h" namespace vkb { Pipeline::Pipeline(vkb::core::DeviceC &device) : device{device} {} Pipeline::Pipeline(Pipeline &&other) : device{other.device}, handle{other.handle}, state{other.state} { other.handle = VK_NULL_HANDLE; } Pipeline::~Pipeline() { // Destroy pipeline if (handle != VK_NULL_HANDLE) { vkDestroyPipeline(device.get_handle(), handle, nullptr); } } VkPipeline Pipeline::get_handle() const { return handle; } const PipelineState &Pipeline::get_state() const { return state; } ComputePipeline::ComputePipeline(vkb::core::DeviceC &device, VkPipelineCache pipeline_cache, PipelineState &pipeline_state) : Pipeline{device} { const ShaderModule *shader_module = pipeline_state.get_pipeline_layout().get_shader_modules().front(); if (shader_module->get_stage() != VK_SHADER_STAGE_COMPUTE_BIT) { throw VulkanException{VK_ERROR_INVALID_SHADER_NV, "Shader module stage is not compute"}; } VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; stage.stage = shader_module->get_stage(); stage.pName = shader_module->get_entry_point().c_str(); // Create the Vulkan handle VkShaderModuleCreateInfo vk_create_info{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; vk_create_info.codeSize = shader_module->get_binary().size() * sizeof(uint32_t); vk_create_info.pCode = shader_module->get_binary().data(); VkResult result = vkCreateShaderModule(device.get_handle(), &vk_create_info, nullptr, &stage.module); if (result != VK_SUCCESS) { throw VulkanException{result}; } device.get_debug_utils().set_debug_name(device.get_handle(), VK_OBJECT_TYPE_SHADER_MODULE, reinterpret_cast(stage.module), shader_module->get_debug_name().c_str()); // Create specialization info from tracked state. std::vector data{}; std::vector map_entries{}; const auto specialization_constant_state = pipeline_state.get_specialization_constant_state().get_specialization_constant_state(); for (const auto specialization_constant : specialization_constant_state) { map_entries.push_back({specialization_constant.first, to_u32(data.size()), specialization_constant.second.size()}); data.insert(data.end(), specialization_constant.second.begin(), specialization_constant.second.end()); } VkSpecializationInfo specialization_info{}; specialization_info.mapEntryCount = to_u32(map_entries.size()); specialization_info.pMapEntries = map_entries.data(); specialization_info.dataSize = data.size(); specialization_info.pData = data.data(); stage.pSpecializationInfo = &specialization_info; VkComputePipelineCreateInfo create_info{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; create_info.layout = pipeline_state.get_pipeline_layout().get_handle(); create_info.stage = stage; result = vkCreateComputePipelines(device.get_handle(), pipeline_cache, 1, &create_info, nullptr, &handle); if (result != VK_SUCCESS) { throw VulkanException{result, "Cannot create ComputePipelines"}; } vkDestroyShaderModule(device.get_handle(), stage.module, nullptr); } GraphicsPipeline::GraphicsPipeline(vkb::core::DeviceC &device, VkPipelineCache pipeline_cache, PipelineState &pipeline_state) : Pipeline{device} { std::vector shader_modules; std::vector stage_create_infos; // Create specialization info from tracked state. This is shared by all shaders. std::vector data{}; std::vector map_entries{}; const auto specialization_constant_state = pipeline_state.get_specialization_constant_state().get_specialization_constant_state(); for (const auto specialization_constant : specialization_constant_state) { map_entries.push_back({specialization_constant.first, to_u32(data.size()), specialization_constant.second.size()}); data.insert(data.end(), specialization_constant.second.begin(), specialization_constant.second.end()); } VkSpecializationInfo specialization_info{}; specialization_info.mapEntryCount = to_u32(map_entries.size()); specialization_info.pMapEntries = map_entries.data(); specialization_info.dataSize = data.size(); specialization_info.pData = data.data(); for (const ShaderModule *shader_module : pipeline_state.get_pipeline_layout().get_shader_modules()) { VkPipelineShaderStageCreateInfo stage_create_info{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; stage_create_info.stage = shader_module->get_stage(); stage_create_info.pName = shader_module->get_entry_point().c_str(); // Create the Vulkan handle VkShaderModuleCreateInfo vk_create_info{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; vk_create_info.codeSize = shader_module->get_binary().size() * sizeof(uint32_t); vk_create_info.pCode = shader_module->get_binary().data(); VkResult result = vkCreateShaderModule(device.get_handle(), &vk_create_info, nullptr, &stage_create_info.module); if (result != VK_SUCCESS) { throw VulkanException{result}; } device.get_debug_utils().set_debug_name(device.get_handle(), VK_OBJECT_TYPE_SHADER_MODULE, reinterpret_cast(stage_create_info.module), shader_module->get_debug_name().c_str()); stage_create_info.pSpecializationInfo = &specialization_info; stage_create_infos.push_back(stage_create_info); shader_modules.push_back(stage_create_info.module); } VkGraphicsPipelineCreateInfo create_info{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; create_info.stageCount = to_u32(stage_create_infos.size()); create_info.pStages = stage_create_infos.data(); VkPipelineVertexInputStateCreateInfo vertex_input_state{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; vertex_input_state.pVertexAttributeDescriptions = pipeline_state.get_vertex_input_state().attributes.data(); vertex_input_state.vertexAttributeDescriptionCount = to_u32(pipeline_state.get_vertex_input_state().attributes.size()); vertex_input_state.pVertexBindingDescriptions = pipeline_state.get_vertex_input_state().bindings.data(); vertex_input_state.vertexBindingDescriptionCount = to_u32(pipeline_state.get_vertex_input_state().bindings.size()); VkPipelineInputAssemblyStateCreateInfo input_assembly_state{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; input_assembly_state.topology = pipeline_state.get_input_assembly_state().topology; input_assembly_state.primitiveRestartEnable = pipeline_state.get_input_assembly_state().primitive_restart_enable; VkPipelineViewportStateCreateInfo viewport_state{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; viewport_state.viewportCount = pipeline_state.get_viewport_state().viewport_count; viewport_state.scissorCount = pipeline_state.get_viewport_state().scissor_count; VkPipelineRasterizationStateCreateInfo rasterization_state{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; rasterization_state.depthClampEnable = pipeline_state.get_rasterization_state().depth_clamp_enable; rasterization_state.rasterizerDiscardEnable = pipeline_state.get_rasterization_state().rasterizer_discard_enable; rasterization_state.polygonMode = pipeline_state.get_rasterization_state().polygon_mode; rasterization_state.cullMode = pipeline_state.get_rasterization_state().cull_mode; rasterization_state.frontFace = pipeline_state.get_rasterization_state().front_face; rasterization_state.depthBiasEnable = pipeline_state.get_rasterization_state().depth_bias_enable; rasterization_state.depthBiasClamp = 1.0f; rasterization_state.depthBiasSlopeFactor = 1.0f; rasterization_state.lineWidth = 1.0f; VkPipelineMultisampleStateCreateInfo multisample_state{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; multisample_state.sampleShadingEnable = pipeline_state.get_multisample_state().sample_shading_enable; multisample_state.rasterizationSamples = pipeline_state.get_multisample_state().rasterization_samples; multisample_state.minSampleShading = pipeline_state.get_multisample_state().min_sample_shading; multisample_state.alphaToCoverageEnable = pipeline_state.get_multisample_state().alpha_to_coverage_enable; multisample_state.alphaToOneEnable = pipeline_state.get_multisample_state().alpha_to_one_enable; if (pipeline_state.get_multisample_state().sample_mask) { multisample_state.pSampleMask = &pipeline_state.get_multisample_state().sample_mask; } VkPipelineDepthStencilStateCreateInfo depth_stencil_state{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; depth_stencil_state.depthTestEnable = pipeline_state.get_depth_stencil_state().depth_test_enable; depth_stencil_state.depthWriteEnable = pipeline_state.get_depth_stencil_state().depth_write_enable; depth_stencil_state.depthCompareOp = pipeline_state.get_depth_stencil_state().depth_compare_op; depth_stencil_state.depthBoundsTestEnable = pipeline_state.get_depth_stencil_state().depth_bounds_test_enable; depth_stencil_state.stencilTestEnable = pipeline_state.get_depth_stencil_state().stencil_test_enable; depth_stencil_state.front.failOp = pipeline_state.get_depth_stencil_state().front.fail_op; depth_stencil_state.front.passOp = pipeline_state.get_depth_stencil_state().front.pass_op; depth_stencil_state.front.depthFailOp = pipeline_state.get_depth_stencil_state().front.depth_fail_op; depth_stencil_state.front.compareOp = pipeline_state.get_depth_stencil_state().front.compare_op; depth_stencil_state.front.compareMask = ~0U; depth_stencil_state.front.writeMask = ~0U; depth_stencil_state.front.reference = ~0U; depth_stencil_state.back.failOp = pipeline_state.get_depth_stencil_state().back.fail_op; depth_stencil_state.back.passOp = pipeline_state.get_depth_stencil_state().back.pass_op; depth_stencil_state.back.depthFailOp = pipeline_state.get_depth_stencil_state().back.depth_fail_op; depth_stencil_state.back.compareOp = pipeline_state.get_depth_stencil_state().back.compare_op; depth_stencil_state.back.compareMask = ~0U; depth_stencil_state.back.writeMask = ~0U; depth_stencil_state.back.reference = ~0U; VkPipelineColorBlendStateCreateInfo color_blend_state{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; color_blend_state.logicOpEnable = pipeline_state.get_color_blend_state().logic_op_enable; color_blend_state.logicOp = pipeline_state.get_color_blend_state().logic_op; color_blend_state.attachmentCount = to_u32(pipeline_state.get_color_blend_state().attachments.size()); color_blend_state.pAttachments = reinterpret_cast(pipeline_state.get_color_blend_state().attachments.data()); color_blend_state.blendConstants[0] = 1.0f; color_blend_state.blendConstants[1] = 1.0f; color_blend_state.blendConstants[2] = 1.0f; color_blend_state.blendConstants[3] = 1.0f; std::array dynamic_states{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_LINE_WIDTH, VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, }; VkPipelineDynamicStateCreateInfo dynamic_state{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; dynamic_state.pDynamicStates = dynamic_states.data(); dynamic_state.dynamicStateCount = to_u32(dynamic_states.size()); create_info.pVertexInputState = &vertex_input_state; create_info.pInputAssemblyState = &input_assembly_state; create_info.pViewportState = &viewport_state; create_info.pRasterizationState = &rasterization_state; create_info.pMultisampleState = &multisample_state; create_info.pDepthStencilState = &depth_stencil_state; create_info.pColorBlendState = &color_blend_state; create_info.pDynamicState = &dynamic_state; create_info.layout = pipeline_state.get_pipeline_layout().get_handle(); create_info.renderPass = pipeline_state.get_render_pass()->get_handle(); create_info.subpass = pipeline_state.get_subpass_index(); auto result = vkCreateGraphicsPipelines(device.get_handle(), pipeline_cache, 1, &create_info, nullptr, &handle); if (result != VK_SUCCESS) { throw VulkanException{result, "Cannot create GraphicsPipelines"}; } for (auto shader_module : shader_modules) { vkDestroyShaderModule(device.get_handle(), shader_module, nullptr); } state = pipeline_state; } } // namespace vkb