308 lines
14 KiB
C++
308 lines
14 KiB
C++
/* 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<uint64_t>(stage.module),
|
|
shader_module->get_debug_name().c_str());
|
|
|
|
// Create specialization info from tracked state.
|
|
std::vector<uint8_t> data{};
|
|
std::vector<VkSpecializationMapEntry> 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<VkShaderModule> shader_modules;
|
|
|
|
std::vector<VkPipelineShaderStageCreateInfo> stage_create_infos;
|
|
|
|
// Create specialization info from tracked state. This is shared by all shaders.
|
|
std::vector<uint8_t> data{};
|
|
std::vector<VkSpecializationMapEntry> 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<uint64_t>(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<const VkPipelineColorBlendAttachmentState *>(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<VkDynamicState, 9> 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
|