tornavis/source/blender/gpu/vulkan/vk_pipeline.cc

209 lines
8.1 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#include "vk_pipeline.hh"
#include "vk_backend.hh"
#include "vk_batch.hh"
#include "vk_context.hh"
#include "vk_framebuffer.hh"
#include "vk_memory.hh"
#include "vk_state_manager.hh"
#include "vk_vertex_attribute_object.hh"
namespace blender::gpu {
VKPipeline::VKPipeline(VKPushConstants &&push_constants)
: active_vk_pipeline_(VK_NULL_HANDLE), push_constants_(std::move(push_constants))
{
}
VKPipeline::VKPipeline(VkPipeline vk_pipeline, VKPushConstants &&push_constants)
: active_vk_pipeline_(vk_pipeline), push_constants_(std::move(push_constants))
{
vk_pipelines_.append(vk_pipeline);
}
VKPipeline::~VKPipeline()
{
VK_ALLOCATION_CALLBACKS
const VKDevice &device = VKBackend::get().device_get();
for (VkPipeline vk_pipeline : vk_pipelines_) {
vkDestroyPipeline(device.device_get(), vk_pipeline, vk_allocation_callbacks);
}
}
VKPipeline VKPipeline::create_compute_pipeline(
VkShaderModule compute_module,
VkPipelineLayout &pipeline_layout,
const VKPushConstants::Layout &push_constants_layout)
{
VK_ALLOCATION_CALLBACKS
const VKDevice &device = VKBackend::get().device_get();
VkComputePipelineCreateInfo pipeline_info = {};
pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
pipeline_info.flags = 0;
pipeline_info.stage = {};
pipeline_info.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
pipeline_info.stage.flags = 0;
pipeline_info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
pipeline_info.stage.module = compute_module;
pipeline_info.layout = pipeline_layout;
pipeline_info.stage.pName = "main";
VkPipeline vk_pipeline;
if (vkCreateComputePipelines(device.device_get(),
nullptr,
1,
&pipeline_info,
vk_allocation_callbacks,
&vk_pipeline) != VK_SUCCESS)
{
return VKPipeline();
}
VKPushConstants push_constants(&push_constants_layout);
return VKPipeline(vk_pipeline, std::move(push_constants));
}
VKPipeline VKPipeline::create_graphics_pipeline(
const VKPushConstants::Layout &push_constants_layout)
{
VKPushConstants push_constants(&push_constants_layout);
return VKPipeline(std::move(push_constants));
}
VkPipeline VKPipeline::vk_handle() const
{
return active_vk_pipeline_;
}
bool VKPipeline::is_valid() const
{
return active_vk_pipeline_ != VK_NULL_HANDLE;
}
void VKPipeline::finalize(VKContext &context,
VkShaderModule vertex_module,
VkShaderModule geometry_module,
VkShaderModule fragment_module,
VkPipelineLayout &pipeline_layout,
const GPUPrimType prim_type,
const VKVertexAttributeObject &vertex_attribute_object)
{
BLI_assert(vertex_module != VK_NULL_HANDLE);
VK_ALLOCATION_CALLBACKS
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages;
VkPipelineShaderStageCreateInfo vertex_stage_info = {};
vertex_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertex_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertex_stage_info.module = vertex_module;
vertex_stage_info.pName = "main";
pipeline_stages.append(vertex_stage_info);
if (geometry_module != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo geometry_stage_info = {};
geometry_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
geometry_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
geometry_stage_info.module = geometry_module;
geometry_stage_info.pName = "main";
pipeline_stages.append(geometry_stage_info);
}
if (fragment_module != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo fragment_stage_info = {};
fragment_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragment_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragment_stage_info.module = fragment_module;
fragment_stage_info.pName = "main";
pipeline_stages.append(fragment_stage_info);
}
VKFrameBuffer &framebuffer = *context.active_framebuffer_get();
framebuffer.vk_render_pass_ensure();
VkGraphicsPipelineCreateInfo pipeline_create_info = {};
pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_create_info.stageCount = pipeline_stages.size();
pipeline_create_info.pStages = pipeline_stages.data();
pipeline_create_info.layout = pipeline_layout;
pipeline_create_info.renderPass = framebuffer.vk_render_pass_get();
pipeline_create_info.subpass = 0;
/* Vertex input state. */
VkPipelineVertexInputStateCreateInfo vertex_input_state = {};
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_state.vertexBindingDescriptionCount = vertex_attribute_object.bindings.size();
vertex_input_state.pVertexBindingDescriptions = vertex_attribute_object.bindings.data();
vertex_input_state.vertexAttributeDescriptionCount = vertex_attribute_object.attributes.size();
vertex_input_state.pVertexAttributeDescriptions = vertex_attribute_object.attributes.data();
pipeline_create_info.pVertexInputState = &vertex_input_state;
/* Input assembly state. */
VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly = {};
pipeline_input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
pipeline_input_assembly.topology = to_vk_primitive_topology(prim_type);
pipeline_input_assembly.primitiveRestartEnable =
ELEM(prim_type, GPU_PRIM_TRIS, GPU_PRIM_LINES, GPU_PRIM_POINTS, GPU_PRIM_LINES_ADJ) ?
VK_FALSE :
VK_TRUE;
pipeline_create_info.pInputAssemblyState = &pipeline_input_assembly;
/* Viewport state. */
VkPipelineViewportStateCreateInfo viewport_state = {};
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
Array<VkViewport, 16> viewports = framebuffer.vk_viewports_get();
viewport_state.pViewports = &viewports[0];
viewport_state.viewportCount = viewports.size();
Array<VkRect2D, 16> scissors = framebuffer.vk_render_areas_get();
viewport_state.pScissors = &scissors[0];
viewport_state.scissorCount = scissors.size();
pipeline_create_info.pViewportState = &viewport_state;
/* Multi-sample state. */
VkPipelineMultisampleStateCreateInfo multisample_state = {};
multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisample_state.minSampleShading = 1.0f;
pipeline_create_info.pMultisampleState = &multisample_state;
/* States from the state manager. */
VKPipelineStateManager &state_manager = state_manager_get();
state_manager.finalize_color_blend_state(framebuffer);
pipeline_create_info.pColorBlendState = &state_manager.pipeline_color_blend_state;
pipeline_create_info.pRasterizationState = &state_manager.rasterization_state;
pipeline_create_info.pDepthStencilState = &state_manager.depth_stencil_state;
const VKDevice &device = VKBackend::get().device_get();
vkCreateGraphicsPipelines(device.device_get(),
VK_NULL_HANDLE,
1,
&pipeline_create_info,
vk_allocation_callbacks,
&active_vk_pipeline_);
/* TODO: we should cache several pipeline instances and detect pipelines we can reuse. This might
* also be done using a VkPipelineCache. For now we just destroy any available pipeline so it
* won't be overwritten by the newly created one. */
vk_pipelines_.append(active_vk_pipeline_);
debug::object_label(active_vk_pipeline_, "GraphicsPipeline");
}
void VKPipeline::bind(VKContext &context, VkPipelineBindPoint vk_pipeline_bind_point)
{
VKCommandBuffers &command_buffers = context.command_buffers_get();
command_buffers.bind(*this, vk_pipeline_bind_point);
}
void VKPipeline::update_push_constants(VKContext &context)
{
push_constants_.update(context);
}
} // namespace blender::gpu