Added builders for pipeline layouts and graphics pipelines.

This commit is contained in:
Diamond-D0gs 2022-10-06 20:34:47 -04:00 committed by Charles Giessen
parent c16de53814
commit a8248e829b
4 changed files with 1337 additions and 148 deletions

View File

@ -6,6 +6,7 @@
#include <string> #include <string>
#include "../tests/common.h" #include "../tests/common.h"
#include "VkPipelineBuilder.h"
#include "example_config.h" #include "example_config.h"
@ -185,6 +186,24 @@ VkShaderModule createShaderModule (Init& init, const std::vector<char>& code) {
return shaderModule; return shaderModule;
} }
int create_graphics_pipeline_new(Init& init, RenderData& data) {
vkb::GraphicsPipelineBuilder gpb{ init.device };
auto vert_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/vert.spv");
auto frag_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/frag.spv");
VkShaderModule vert_module = createShaderModule(init, vert_code);
VkShaderModule frag_module = createShaderModule(init, frag_code);
if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) {
std::cout << "failed to create shader module\n";
return -1; // failed to create shader modules
}
gpb.set_vertex_shader_entrypoint_name()
return 0;
}
int create_graphics_pipeline(Init& init, RenderData& data) { int create_graphics_pipeline(Init& init, RenderData& data) {
auto vert_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/vert.spv"); auto vert_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/vert.spv");
auto frag_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/frag.spv"); auto frag_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/frag.spv");
@ -255,8 +274,8 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | colorBlendAttachment.colorWriteMask =
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_FALSE; colorBlendAttachment.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo color_blending = {}; VkPipelineColorBlendStateCreateInfo color_blending = {};
@ -275,8 +294,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
pipeline_layout_info.setLayoutCount = 0; pipeline_layout_info.setLayoutCount = 0;
pipeline_layout_info.pushConstantRangeCount = 0; pipeline_layout_info.pushConstantRangeCount = 0;
if (init->vkCreatePipelineLayout ( if (init->vkCreatePipelineLayout(init.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) {
init.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) {
std::cout << "failed to create pipeline layout\n"; std::cout << "failed to create pipeline layout\n";
return -1; // failed to create pipeline layout return -1; // failed to create pipeline layout
} }
@ -304,8 +322,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
pipeline_info.subpass = 0; pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = VK_NULL_HANDLE; pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
if (init->vkCreateGraphicsPipelines ( if (init->vkCreateGraphicsPipelines(init.device, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &data.graphics_pipeline) != VK_SUCCESS) {
init.device, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &data.graphics_pipeline) != VK_SUCCESS) {
std::cout << "failed to create pipline\n"; std::cout << "failed to create pipline\n";
return -1; // failed to create graphics pipeline return -1; // failed to create graphics pipeline
} }
@ -460,12 +477,8 @@ int draw_frame (Init& init, RenderData& data) {
init->vkWaitForFences(init.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX); init->vkWaitForFences(init.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX);
uint32_t image_index = 0; uint32_t image_index = 0;
VkResult result = init->vkAcquireNextImageKHR (init.device, VkResult result = init->vkAcquireNextImageKHR(
init.swapchain, init.device, init.swapchain, UINT64_MAX, data.available_semaphores[data.current_frame], VK_NULL_HANDLE, &image_index);
UINT64_MAX,
data.available_semaphores[data.current_frame],
VK_NULL_HANDLE,
&image_index);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR) {
return recreate_swapchain(init, data); return recreate_swapchain(init, data);

View File

@ -15,6 +15,7 @@
*/ */
#include "VkBootstrap.h" #include "VkBootstrap.h"
#include "VkPipelineBuilder.h"
#include <cstring> #include <cstring>
@ -365,11 +366,23 @@ struct DeviceErrorCategory : std::error_category {
const DeviceErrorCategory device_error_category; const DeviceErrorCategory device_error_category;
struct SwapchainErrorCategory : std::error_category { struct SwapchainErrorCategory : std::error_category {
const char* name() const noexcept override { return "vbk_swapchain"; } const char* name() const noexcept override { return "vkb_swapchain"; }
std::string message(int err) const override { return to_string(static_cast<SwapchainError>(err)); } std::string message(int err) const override { return to_string(static_cast<SwapchainError>(err)); }
}; };
const SwapchainErrorCategory swapchain_error_category; const SwapchainErrorCategory swapchain_error_category;
struct PipelineLayoutErrorCategory : std::error_category {
const char* name() const noexcept override { return "vkb_pipeline_layout"; }
std::string message(int err) const override { return to_string(static_cast<PipelineLayoutError>(err)); }
};
const PipelineLayoutErrorCategory pipeline_layout_error_category;
struct GraphicsPipelineErrorCategory : std::error_category {
const char* name() const noexcept override { return "vkb_graphics_pipeline"; }
std::string message(int err) const override { return to_string(static_cast<GraphicsPipelineError>(err)); }
};
const GraphicsPipelineErrorCategory graphics_pipeline_error_category;
} // namespace detail } // namespace detail
std::error_code make_error_code(InstanceError instance_error) { std::error_code make_error_code(InstanceError instance_error) {
@ -387,6 +400,13 @@ std::error_code make_error_code(DeviceError device_error) {
std::error_code make_error_code(SwapchainError swapchain_error) { std::error_code make_error_code(SwapchainError swapchain_error) {
return { static_cast<int>(swapchain_error), detail::swapchain_error_category }; return { static_cast<int>(swapchain_error), detail::swapchain_error_category };
} }
std::error_code make_error_code(PipelineLayoutError pipeline_layout_error) {
return { static_cast<int>(pipeline_layout_error), detail::pipeline_layout_error_category };
}
std::error_code make_error_code(GraphicsPipelineError graphics_pipeline_error) {
return { static_cast<int>(graphics_pipeline_error), detail::graphics_pipeline_error_category };
}
#define CASE_TO_STRING(CATEGORY, TYPE) \ #define CASE_TO_STRING(CATEGORY, TYPE) \
case CATEGORY::TYPE: \ case CATEGORY::TYPE: \
return #TYPE; return #TYPE;
@ -446,6 +466,26 @@ const char* to_string(SwapchainError err) {
return ""; return "";
} }
} }
const char* to_string(PipelineLayoutError err) {
switch (err) {
case PipelineLayoutError::device_handle_not_provided:
return "device_handle_not_provided";
case PipelineLayoutError::failed_to_create_pipeline_layout:
return "failed_to_create_pipeline_layout";
default:
return "";
}
}
const char* to_string(GraphicsPipelineError err) {
switch (err) {
case GraphicsPipelineError::device_handle_not_provided:
return "device_handle_not_provided";
case GraphicsPipelineError::failed_to_create_graphics_pipeline:
return "failed_to_create_graphics_pipeline";
default:
return "";
}
}
Result<SystemInfo> SystemInfo::get_system_info() { Result<SystemInfo> SystemInfo::get_system_info() {
if (!detail::vulkan_functions().init_vulkan_funcs(nullptr)) { if (!detail::vulkan_functions().init_vulkan_funcs(nullptr)) {
@ -2017,4 +2057,741 @@ void SwapchainBuilder::add_desired_present_modes(std::vector<VkPresentModeKHR>&
modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
modes.push_back(VK_PRESENT_MODE_FIFO_KHR); modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
} }
// ---- PipelineLayout ---- //
PipelineLayoutBuilder& PipelineLayoutBuilder::set_pipeline_layout_flags(VkPipelineLayoutCreateFlags layout_flags) {
info.flags = layout_flags;
return *this;
}
PipelineLayoutBuilder::PipelineLayoutBuilder(Device const& device) {
info.device = device.device;
detail::vulkan_functions().get_device_proc_addr(info.device, info.pipeline_layout_create_proc, "vkCreatePipelineLayout");
}
PipelineLayoutBuilder::PipelineLayoutBuilder(VkDevice const device) {
info.device = device;
detail::vulkan_functions().get_device_proc_addr(info.device, info.pipeline_layout_create_proc, "vkCreatePipelineLayout");
}
PipelineLayoutBuilder& PipelineLayoutBuilder::add_descriptor_layout(VkDescriptorSetLayout descriptor_set_layout) {
info.descriptor_layouts.push_back(descriptor_set_layout);
return *this;
}
PipelineLayoutBuilder& PipelineLayoutBuilder::add_descriptor_layouts(std::vector<VkDescriptorSetLayout> descriptor_set_layouts) {
for (const auto& layout : descriptor_set_layouts)
info.descriptor_layouts.push_back(layout);
return *this;
}
PipelineLayoutBuilder& PipelineLayoutBuilder::clear_descriptor_layouts() {
info.descriptor_layouts.clear();
return *this;
}
PipelineLayoutBuilder& PipelineLayoutBuilder::add_push_constant_range(VkPushConstantRange push_constant_range) {
info.push_constant_ranges.push_back(push_constant_range);
return *this;
}
PipelineLayoutBuilder& PipelineLayoutBuilder::add_push_constant_ranges(std::vector<VkPushConstantRange> push_constant_ranges) {
for (const auto& range : push_constant_ranges)
info.push_constant_ranges.push_back(range);
return *this;
}
PipelineLayoutBuilder& PipelineLayoutBuilder::clear_push_constant_ranges() {
info.push_constant_ranges.clear();
return *this;
}
PipelineLayoutBuilder& PipelineLayoutBuilder::clear_pNext_chain() {
info.pNext_chain.clear();
return *this;
}
PipelineLayoutBuilder& PipelineLayoutBuilder::set_allocation_callbacks(VkAllocationCallbacks* callbacks) {
info.allocation_callbacks = callbacks;
return *this;
}
Result<VkPipelineLayout> PipelineLayoutBuilder::build() const {
if (info.device == VK_NULL_HANDLE) return Error{ PipelineLayoutError::device_handle_not_provided };
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
detail::setup_pNext_chain(pipeline_layout_create_info, info.pNext_chain);
#if !defined(NDEBUG)
for (auto& node : info.pNext_chain)
assert(node->sType != VK_STRUCTURE_TYPE_APPLICATION_INFO);
#endif
pipeline_layout_create_info.flags = info.flags;
pipeline_layout_create_info.setLayoutCount = static_cast<uint32_t>(info.descriptor_layouts.size());
pipeline_layout_create_info.pSetLayouts = info.descriptor_layouts.data();
pipeline_layout_create_info.pushConstantRangeCount = static_cast<uint32_t>(info.push_constant_ranges.size());
pipeline_layout_create_info.pPushConstantRanges = info.push_constant_ranges.data();
VkPipelineLayout pipeline_layout{};
VkResult res = info.pipeline_layout_create_proc(
info.device, &pipeline_layout_create_info, info.allocation_callbacks, &pipeline_layout);
if (res != VK_SUCCESS) return Error{ PipelineLayoutError::failed_to_create_pipeline_layout, res };
return pipeline_layout;
}
// ---- Graphics Pipeline ---- //
GraphicsPipelineBuilder::GraphicsPipelineBuilder(Device const& device, VkPipelineCache pipeline_cache) {
info.device = device.device;
info.pipeline_cache = pipeline_cache;
detail::vulkan_functions().get_device_proc_addr(info.device, info.graphics_pipeline_create_proc, "vkCreateGraphicsPipelines");
}
GraphicsPipelineBuilder::GraphicsPipelineBuilder(VkDevice const device, VkPipelineCache pipeline_cache) {
info.device = device;
info.pipeline_cache = pipeline_cache;
detail::vulkan_functions().get_device_proc_addr(info.device, info.graphics_pipeline_create_proc, "vkCreateGraphicsPipelines");
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_allocation_callbacks(VkAllocationCallbacks* callbacks) {
info.allocation_callbacks = callbacks;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_pNext() {
info.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_pipeline_create_flags(VkPipelineCreateFlags pipeline_create_flags) {
info.flags = pipeline_create_flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_pipeline_layout(VkPipelineLayout pipeline_layout) {
info.pipeline_layout = pipeline_layout;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_renderpass(VkRenderPass renderpass, uint32_t subpass_index) {
info.renderpass = renderpass;
info.subpass = subpass_index;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_base_pipeline(VkPipeline base_pipeline, uint32_t base_pipeline_index) {
info.base_pipeline = base_pipeline;
info.base_pipeline_index = base_pipeline_index;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_additional_shader_stage(VkPipelineShaderStageCreateInfo& shader_stage_info) {
info.additional_shader_stages.push_back(shader_stage_info);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_additional_shader_stages(
std::vector<VkPipelineShaderStageCreateInfo> shader_stage_infos) {
for (auto shader_stage_info : shader_stage_infos)
info.additional_shader_stages.push_back(shader_stage_info);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_additional_shader_stages() {
info.additional_shader_stages.clear();
return *this;
}
// Vertex input state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_vertex_input_pNext() {
info.vertex_input.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_vertex_input_binding_desc(VkVertexInputBindingDescription vertex_input_binding_desc) {
info.vertex_input.binding_descs.push_back(vertex_input_binding_desc);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_vertex_input_binding_descs(
std::vector<VkVertexInputBindingDescription> vertex_input_binding_descs) {
for (auto binding_desc : vertex_input_binding_descs)
info.vertex_input.binding_descs.push_back(binding_desc);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_vertex_input_binding_descs() {
info.vertex_input.binding_descs.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_vertex_input_attrib_desc(VkVertexInputAttributeDescription vertex_input_attrib_desc) {
info.vertex_input.attrib_descs.push_back(vertex_input_attrib_desc);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_vertex_input_attrib_descs(
std::vector<VkVertexInputAttributeDescription> vertex_input_attrib_descs) {
for (auto attrib_desc : vertex_input_attrib_descs)
info.vertex_input.attrib_descs.push_back(attrib_desc);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_vertex_input_attrib_descs() {
info.vertex_input.attrib_descs.clear();
return *this;
}
// Input assembly state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_input_assembly_primitive_topology(VkPrimitiveTopology topology) {
info.input_assembly.topology = topology;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_input_assembly_primitive_restart(bool enable_primitive_restart) {
info.input_assembly.primitiveRestartEnable = enable_primitive_restart ? VK_TRUE : VK_FALSE;
return *this;
}
// Vertex shader
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_vertex_shader_pNext() {
info.vertex_shader.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_vertex_shader_flags(VkPipelineShaderStageCreateFlags flags) {
info.vertex_shader.flags = flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_vertex_shader_module(VkShaderModule shader_module) {
info.vertex_shader.shader_module = shader_module;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_vertex_shader_name(const char* name) {
info.vertex_shader.name = name;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_vertex_shader_specialization_info(VkSpecializationInfo& specialization_info) {
info.vertex_shader.specialization_info = specialization_info;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_vertex_shader() {
info.vertex_shader.pNext_chain.clear();
info.vertex_shader.flags = 0;
info.vertex_shader.shader_module = VK_NULL_HANDLE;
info.vertex_shader.name = "";
info.vertex_shader.specialization_info = {};
return *this;
}
// Tessellation control shader
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_tessellation_control_shader_pNext() {
info.tessellation_control_shader.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_control_shader_flags(VkPipelineShaderStageCreateFlags flags) {
info.tessellation_control_shader.flags = flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_control_shader_module(VkShaderModule shader_module) {
info.tessellation_control_shader.shader_module = shader_module;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_control_shader_name(const char* name) {
info.tessellation_control_shader.name = name;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_control_shader_specialization_info(
VkSpecializationInfo& specialization_info) {
info.tessellation_control_shader.specialization_info = specialization_info;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_tessellation_control_shader() {
info.tessellation_control_shader.pNext_chain.clear();
info.tessellation_control_shader.flags = 0;
info.tessellation_control_shader.shader_module = VK_NULL_HANDLE;
info.tessellation_control_shader.name = "";
info.tessellation_control_shader.specialization_info = {};
return *this;
}
// Tessellation evaluation shader
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_tessellation_eval_shader_pNext() {
info.tessellation_eval_shader.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_eval_shader_flags(VkPipelineShaderStageCreateFlags flags) {
info.tessellation_eval_shader.flags = flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_eval_shader_module(VkShaderModule shader_module) {
info.tessellation_eval_shader.shader_module = shader_module;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_eval_shader_name(const char* name) {
info.tessellation_eval_shader.name = name;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_eval_shader_specialization_info(
VkSpecializationInfo& specialization_info) {
info.tessellation_eval_shader.specialization_info = specialization_info;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_tessellation_eval_shader() {
info.tessellation_eval_shader.pNext_chain.clear();
info.tessellation_eval_shader.flags = 0;
info.tessellation_eval_shader.shader_module = VK_NULL_HANDLE;
info.tessellation_eval_shader.name = "";
info.tessellation_eval_shader.specialization_info = {};
return *this;
}
// Tessellation state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_tessellation_state_pNext() {
info.tessellation_state.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_tessellation_state_patch_control_points(uint32_t patch_control_points) {
info.tessellation_state.patch_control_points = patch_control_points;
return *this;
}
// Geometry shader
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_geometry_shader_pNext() {
info.geometry_shader.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_geometry_shader_flags(VkPipelineShaderStageCreateFlags flags) {
info.geometry_shader.flags = flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_geometry_shader_module(VkShaderModule shader_module) {
info.geometry_shader.shader_module = shader_module;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_geometry_shader_name(const char* name) {
info.geometry_shader.name = name;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_geometry_shader_specialization_info(VkSpecializationInfo& specialization_info) {
info.geometry_shader.specialization_info = specialization_info;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_geometry_shader() {
info.geometry_shader.pNext_chain.clear();
info.geometry_shader.flags = 0;
info.geometry_shader.shader_module = VK_NULL_HANDLE;
info.geometry_shader.name = "";
info.geometry_shader.specialization_info = {};
return *this;
}
// Viewport state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_viewport_state_pNext() {
info.viewport_state.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_viewport_state_viewport(VkViewport viewport) {
info.viewport_state.viewports.push_back(viewport);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_viewport_state_viewports(std::vector<VkViewport> viewports) {
for (auto viewport : viewports)
info.viewport_state.viewports.push_back(viewport);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_viewport_state_viewports() {
info.viewport_state.viewports.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_viewport_state_scissor(VkRect2D scissor) {
info.viewport_state.scissors.push_back(scissor);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_viewport_state_scissors(std::vector<VkRect2D> scissors) {
for (auto scissor : scissors)
info.viewport_state.scissors.push_back(scissor);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_viewport_state_scissors() {
info.viewport_state.scissors.clear();
return *this;
}
// Fragment shader
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_fragment_shader_pNext() {
info.fragment_shader.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_fragment_shader_flags(VkPipelineShaderStageCreateFlags flags) {
info.fragment_shader.flags = flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_fragment_shader_module(VkShaderModule shader_module) {
info.fragment_shader.shader_module = shader_module;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_fragment_shader_name(const char* name) {
info.fragment_shader.name = name;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_fragment_shader_specialization_info(VkSpecializationInfo& specialization_info) {
info.fragment_shader.specialization_info = specialization_info;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_fragment_shader() {
info.fragment_shader.pNext_chain.clear();
info.fragment_shader.flags = 0;
info.fragment_shader.shader_module = VK_NULL_HANDLE;
info.fragment_shader.name = "";
info.fragment_shader.specialization_info = {};
return *this;
}
// Rasterization state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_rasterization_state_pNext() {
info.rasterization_state.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_rasterization_state_depth_clamp(bool enable_depth_clamp) {
info.rasterization_state.depth_clamp_enable = enable_depth_clamp ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_rasterization_state_discard(bool enable_rasterizer_discard) {
info.rasterization_state.rasterizer_discard_enable = enable_rasterizer_discard ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_rasterization_state_polygon_mode(VkPolygonMode polygon_mode) {
info.rasterization_state.polygon_mode = polygon_mode;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_rasterization_state_cull_mode_flags(VkCullModeFlags cull_mode_flags) {
info.rasterization_state.cull_mode_flags = cull_mode_flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_rasterization_state_front_face(VkFrontFace front_face) {
info.rasterization_state.front_face = front_face;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_rasterization_state_depth_bias(bool enable_depth_bias) {
info.rasterization_state.depth_bias_enable = enable_depth_bias ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_rasterization_state_depth_bias_constant_factor(float depth_bias_constant_factor) {
info.rasterization_state.depth_bias_constant_factor = depth_bias_constant_factor;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_rasterization_state_depth_bias_clamp(float depth_bias_clamp) {
info.rasterization_state.depth_bias_clamp = depth_bias_clamp;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_rasterization_state_depth_bias_slope_factor(float depth_bias_slope_factor) {
info.rasterization_state.depth_bias_slope_factor = depth_bias_slope_factor;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_rasterization_state_line_width(float line_width) {
info.rasterization_state.line_width = line_width;
return *this;
}
// Multisample state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_multisample_state_pNext() {
info.multisample_state.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_multisample_state_sample_count(VkSampleCountFlagBits sample_count) {
info.multisample_state.sample_count = sample_count;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_multisample_state_sample_shading(bool enable_sample_shading) {
info.multisample_state.sample_shading = enable_sample_shading ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_multisample_state_min_sample_shading(float min_sample_shading) {
info.multisample_state.min_sample_shading = min_sample_shading;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_multisample_state_sample_mask(VkSampleMask sample_mask) {
info.multisample_state.sample_mask = sample_mask;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_multisample_state_alpha_to_coverage(bool enable_alpha_to_coverage) {
info.multisample_state.alpha_to_coverage = enable_alpha_to_coverage ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_multisample_state_alpha_to_one(bool enable_alpha_to_one) {
info.multisample_state.alpha_to_one = enable_alpha_to_one ? VK_TRUE : VK_FALSE;
return *this;
}
// Depth stencil state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_depth_stencil_state_pNext() {
info.depth_stencil_state.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_depth_stencil_state_flags(VkPipelineDepthStencilStateCreateFlags flags) {
info.depth_stencil_state.flags = flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_depth_stencil_depth_testing(bool enable_depth_testing) {
info.depth_stencil_state.depth_test = enable_depth_testing ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_depth_stencil_depth_write(bool enable_depth_write) {
info.depth_stencil_state.depth_write = enable_depth_write ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_depth_stencil_compare_op(VkCompareOp compare_op) {
info.depth_stencil_state.depth_compare_operation = compare_op;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_depth_stencil_depth_bounds_test(bool enable_depth_bounds_test) {
info.depth_stencil_state.depth_bounds_test = enable_depth_bounds_test ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_depth_stencil_stencil_test(bool enable_stencil_test) {
info.depth_stencil_state.stencil_test = enable_stencil_test ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_depth_stencil_front_stencil_op_state(VkStencilOpState front) {
info.depth_stencil_state.front_stencil_op_state = front;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_depth_stencil_back_stencil_op_state(VkStencilOpState back) {
info.depth_stencil_state.back_stencil_op_state = back;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_depth_stencil_min_depth_bounds(float min_depth_bounds) {
info.depth_stencil_state.min_depth_bounds = min_depth_bounds;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_depth_stencil_max_depth_bounds(float max_depth_bounds) {
info.depth_stencil_state.max_depth_bounds = max_depth_bounds;
return *this;
}
// Color blend state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_color_blend_state_pNext() {
info.color_blend_state.pNext_chain.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_color_blend_state_flags(VkPipelineColorBlendStateCreateFlags flags) {
info.color_blend_state.flags = flags;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::enable_color_blend_state_logic_op(bool enable_logic_op) {
info.color_blend_state.logic_op_enable = enable_logic_op ? VK_TRUE : VK_FALSE;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_color_blend_state_logic_op(VkLogicOp logic_op) {
info.color_blend_state.logic_op = logic_op;
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_color_blend_state_color_blend_attachment(
VkPipelineColorBlendAttachmentState attachment) {
info.color_blend_state.attachments.push_back(attachment);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_color_blend_state_color_blend_attachments(
std::vector<VkPipelineColorBlendAttachmentState> attachments) {
for (auto attachment : attachments)
info.color_blend_state.attachments.push_back(attachment);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_color_blend_state_color_blend_attachments() {
info.color_blend_state.attachments.clear();
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::set_color_blend_state_blend_constants(
float red, float green, float blue, float alpha) {
info.color_blend_state.blend_constants[0] = red;
info.color_blend_state.blend_constants[1] = green;
info.color_blend_state.blend_constants[2] = blue;
info.color_blend_state.blend_constants[3] = alpha;
return *this;
}
// Dynamic state
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_dynamic_state(VkDynamicState& dynamic_state) {
info.dynamic_state.dynamic_states.push_back(dynamic_state);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::add_dynamic_states(std::vector<VkDynamicState> dynamic_states) {
for (auto& dynamic_state : dynamic_states)
info.dynamic_state.dynamic_states.push_back(dynamic_state);
return *this;
}
GraphicsPipelineBuilder& GraphicsPipelineBuilder::clear_dynamic_states() {
info.dynamic_state.dynamic_states.clear();
return *this;
}
// Build
Result<VkPipeline> GraphicsPipelineBuilder::build() const {
if (info.device == VK_NULL_HANDLE) return Error{ GraphicsPipelineError::device_handle_not_provided };
// Define everything that is not defined within another struct.
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = {};
graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
detail::setup_pNext_chain(graphics_pipeline_create_info, info.pNext_chain);
graphics_pipeline_create_info.flags = info.flags;
graphics_pipeline_create_info.layout = info.pipeline_layout;
graphics_pipeline_create_info.renderPass = info.renderpass;
graphics_pipeline_create_info.subpass = info.subpass;
graphics_pipeline_create_info.basePipelineHandle = info.base_pipeline;
graphics_pipeline_create_info.basePipelineIndex = static_cast<int32_t>(info.base_pipeline_index);
// Begin preparing the shader stages to be added to creation struct.
std::vector<VkPipelineShaderStageCreateInfo> shader_stages;
// The inclusion of a stage is determined by the shader module being set.
if (info.vertex_shader.shader_module != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo vertex_shader = {};
vertex_shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
detail::setup_pNext_chain(vertex_shader, info.vertex_shader.pNext_chain);
vertex_shader.flags = info.vertex_shader.flags;
vertex_shader.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertex_shader.module = info.vertex_shader.shader_module;
vertex_shader.pName = info.vertex_shader.name;
vertex_shader.pSpecializationInfo = &info.vertex_shader.specialization_info;
shader_stages.push_back(vertex_shader);
}
if (info.tessellation_control_shader.shader_module != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo tessellation_control_shader = {};
tessellation_control_shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
detail::setup_pNext_chain(tessellation_control_shader, info.tessellation_control_shader.pNext_chain);
tessellation_control_shader.flags = info.tessellation_control_shader.flags;
tessellation_control_shader.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
tessellation_control_shader.module = info.tessellation_control_shader.shader_module;
tessellation_control_shader.pName = info.tessellation_control_shader.name;
tessellation_control_shader.pSpecializationInfo = &info.tessellation_control_shader.specialization_info;
shader_stages.push_back(tessellation_control_shader);
}
if (info.tessellation_eval_shader.shader_module != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo tessellation_eval_shader = {};
tessellation_eval_shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
detail::setup_pNext_chain(tessellation_eval_shader, info.tessellation_eval_shader.pNext_chain);
tessellation_eval_shader.flags = info.tessellation_eval_shader.flags;
tessellation_eval_shader.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
tessellation_eval_shader.module = info.tessellation_eval_shader.shader_module;
tessellation_eval_shader.pName = info.tessellation_eval_shader.name;
tessellation_eval_shader.pSpecializationInfo = &info.tessellation_eval_shader.specialization_info;
shader_stages.push_back(tessellation_eval_shader);
}
if (info.geometry_shader.shader_module != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo geometry_shader = {};
geometry_shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
detail::setup_pNext_chain(geometry_shader, info.geometry_shader.pNext_chain);
geometry_shader.flags = info.geometry_shader.flags;
geometry_shader.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
geometry_shader.module = info.geometry_shader.shader_module;
geometry_shader.pName = info.geometry_shader.name;
geometry_shader.pSpecializationInfo = &info.geometry_shader.specialization_info;
shader_stages.push_back(geometry_shader);
}
if (info.fragment_shader.shader_module != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo fragment_shader = {};
fragment_shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
detail::setup_pNext_chain(fragment_shader, info.fragment_shader.pNext_chain);
fragment_shader.flags = info.fragment_shader.flags;
fragment_shader.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragment_shader.module = info.fragment_shader.shader_module;
fragment_shader.pName = info.fragment_shader.name;
fragment_shader.pSpecializationInfo = &info.fragment_shader.specialization_info;
shader_stages.push_back(fragment_shader);
}
// Append any additional shader stages that were defined externally
for (auto shader_stage : info.additional_shader_stages)
shader_stages.push_back(shader_stage);
// Append shader stages to the creation struct.
graphics_pipeline_create_info.stageCount = static_cast<uint32_t>(shader_stages.size());
graphics_pipeline_create_info.pStages = shader_stages.data();
// Prepare the state structs.
// Vertex input
VkPipelineVertexInputStateCreateInfo vertex_input = {};
vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
detail::setup_pNext_chain(vertex_input, info.vertex_input.pNext_chain);
vertex_input.vertexBindingDescriptionCount = static_cast<uint32_t>(info.vertex_input.binding_descs.size());
vertex_input.pVertexBindingDescriptions = info.vertex_input.binding_descs.data();
vertex_input.vertexAttributeDescriptionCount = static_cast<uint32_t>(info.vertex_input.attrib_descs.size());
vertex_input.pVertexAttributeDescriptions = info.vertex_input.attrib_descs.data();
// Input Assembly
VkPipelineInputAssemblyStateCreateInfo input_assembly = {};
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly.topology = info.input_assembly.topology;
input_assembly.primitiveRestartEnable = info.input_assembly.primitiveRestartEnable;
// Tessellation state
VkPipelineTessellationStateCreateInfo tessellation_state = {};
tessellation_state.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
detail::setup_pNext_chain(tessellation_state, info.tessellation_state.pNext_chain);
tessellation_state.patchControlPoints = info.tessellation_state.patch_control_points;
// Viewport state
VkPipelineViewportStateCreateInfo viewport_state = {};
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
detail::setup_pNext_chain(viewport_state, info.viewport_state.pNext_chain);
viewport_state.viewportCount = static_cast<uint32_t>(info.viewport_state.viewports.size());
viewport_state.pViewports = info.viewport_state.viewports.data();
viewport_state.scissorCount = static_cast<uint32_t>(info.viewport_state.scissors.size());
viewport_state.pScissors = info.viewport_state.scissors.data();
// Rasterization state
VkPipelineRasterizationStateCreateInfo rasterization_state = {};
rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
detail::setup_pNext_chain(rasterization_state, info.rasterization_state.pNext_chain);
rasterization_state.depthClampEnable = info.rasterization_state.depth_clamp_enable;
rasterization_state.rasterizerDiscardEnable = info.rasterization_state.rasterizer_discard_enable;
rasterization_state.polygonMode = info.rasterization_state.polygon_mode;
rasterization_state.cullMode = info.rasterization_state.cull_mode_flags;
rasterization_state.frontFace = info.rasterization_state.front_face;
rasterization_state.depthBiasEnable = info.rasterization_state.depth_bias_enable;
rasterization_state.depthBiasConstantFactor = info.rasterization_state.depth_bias_constant_factor;
rasterization_state.depthBiasClamp = info.rasterization_state.depth_bias_clamp;
rasterization_state.depthBiasSlopeFactor = info.rasterization_state.depth_bias_slope_factor;
rasterization_state.lineWidth = info.rasterization_state.line_width;
// Multisample state
VkPipelineMultisampleStateCreateInfo multisample_state = {};
multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
detail::setup_pNext_chain(multisample_state, info.multisample_state.pNext_chain);
multisample_state.rasterizationSamples = info.multisample_state.sample_count;
multisample_state.sampleShadingEnable = info.multisample_state.sample_shading;
multisample_state.minSampleShading = info.multisample_state.min_sample_shading;
multisample_state.pSampleMask = &info.multisample_state.sample_mask;
multisample_state.alphaToCoverageEnable = info.multisample_state.alpha_to_coverage;
multisample_state.alphaToOneEnable = info.multisample_state.alpha_to_one;
// Depth stencil state
VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {};
depth_stencil_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
detail::setup_pNext_chain(depth_stencil_state, info.depth_stencil_state.pNext_chain);
depth_stencil_state.flags = info.depth_stencil_state.flags;
depth_stencil_state.depthTestEnable = info.depth_stencil_state.depth_test;
depth_stencil_state.depthWriteEnable = info.depth_stencil_state.depth_write;
depth_stencil_state.depthCompareOp = info.depth_stencil_state.depth_compare_operation;
depth_stencil_state.stencilTestEnable = info.depth_stencil_state.stencil_test;
depth_stencil_state.front = info.depth_stencil_state.front_stencil_op_state;
depth_stencil_state.back = info.depth_stencil_state.back_stencil_op_state;
depth_stencil_state.minDepthBounds = info.depth_stencil_state.min_depth_bounds;
depth_stencil_state.maxDepthBounds = info.depth_stencil_state.max_depth_bounds;
// Color blend state
VkPipelineColorBlendStateCreateInfo color_blend_state = {};
color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
detail::setup_pNext_chain(color_blend_state, info.color_blend_state.pNext_chain);
color_blend_state.flags = info.color_blend_state.flags;
color_blend_state.logicOpEnable = info.color_blend_state.logic_op_enable;
color_blend_state.logicOp = info.color_blend_state.logic_op;
color_blend_state.attachmentCount = static_cast<uint32_t>(info.color_blend_state.attachments.size());
color_blend_state.pAttachments = info.color_blend_state.attachments.data();
memcpy(color_blend_state.blendConstants, info.color_blend_state.blend_constants, (sizeof(float) * 4));
// Dynamic state
VkPipelineDynamicStateCreateInfo dynamic_state = {};
dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state.dynamicStateCount = static_cast<uint32_t>(info.dynamic_state.dynamic_states.size());
dynamic_state.pDynamicStates = info.dynamic_state.dynamic_states.data();
// Append all the state structs to the creation struct.
graphics_pipeline_create_info.pVertexInputState = &vertex_input;
graphics_pipeline_create_info.pInputAssemblyState = &input_assembly;
graphics_pipeline_create_info.pTessellationState = &tessellation_state;
graphics_pipeline_create_info.pViewportState = &viewport_state;
graphics_pipeline_create_info.pRasterizationState = &rasterization_state;
graphics_pipeline_create_info.pMultisampleState = &multisample_state;
graphics_pipeline_create_info.pColorBlendState = &color_blend_state;
graphics_pipeline_create_info.pDynamicState = &dynamic_state;
VkPipeline pipeline = VK_NULL_HANDLE;
VkResult res = info.graphics_pipeline_create_proc(
info.device, info.pipeline_cache, 1, &graphics_pipeline_create_info, info.allocation_callbacks, &pipeline);
if (res != VK_SUCCESS) return Error{ GraphicsPipelineError::failed_to_create_graphics_pipeline };
return pipeline;
}
} // namespace vkb } // namespace vkb

View File

@ -214,12 +214,22 @@ enum class SwapchainError {
failed_create_swapchain_image_views, failed_create_swapchain_image_views,
required_min_image_count_too_low, required_min_image_count_too_low,
}; };
enum class PipelineLayoutError {
device_handle_not_provided,
failed_to_create_pipeline_layout,
};
enum class GraphicsPipelineError {
device_handle_not_provided,
failed_to_create_graphics_pipeline,
};
std::error_code make_error_code(InstanceError instance_error); std::error_code make_error_code(InstanceError instance_error);
std::error_code make_error_code(PhysicalDeviceError physical_device_error); std::error_code make_error_code(PhysicalDeviceError physical_device_error);
std::error_code make_error_code(QueueError queue_error); std::error_code make_error_code(QueueError queue_error);
std::error_code make_error_code(DeviceError device_error); std::error_code make_error_code(DeviceError device_error);
std::error_code make_error_code(SwapchainError swapchain_error); std::error_code make_error_code(SwapchainError swapchain_error);
std::error_code make_error_code(PipelineLayoutError pipeline_layout_error);
std::error_code make_error_code(GraphicsPipelineError graphics_pipeline_error);
const char* to_string_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT s); const char* to_string_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT s);
const char* to_string_message_type(VkDebugUtilsMessageTypeFlagsEXT s); const char* to_string_message_type(VkDebugUtilsMessageTypeFlagsEXT s);
@ -229,6 +239,8 @@ const char* to_string(PhysicalDeviceError err);
const char* to_string(QueueError err); const char* to_string(QueueError err);
const char* to_string(DeviceError err); const char* to_string(DeviceError err);
const char* to_string(SwapchainError err); const char* to_string(SwapchainError err);
const char* to_string(PipelineLayoutError err);
const char* to_string(GraphicsPipelineError err);
// Gathers useful information about the available vulkan capabilities, like layers and instance // Gathers useful information about the available vulkan capabilities, like layers and instance
// extensions. Use this for enabling features conditionally, ie if you would like an extension but // extensions. Use this for enabling features conditionally, ie if you would like an extension but
@ -938,8 +950,7 @@ class SwapchainBuilder {
} info; } info;
}; };
} // namespace vkb }; // namespace vkb
namespace std { namespace std {
template <> struct is_error_code_enum<vkb::InstanceError> : true_type {}; template <> struct is_error_code_enum<vkb::InstanceError> : true_type {};
@ -947,4 +958,6 @@ template <> struct is_error_code_enum<vkb::PhysicalDeviceError> : true_type {};
template <> struct is_error_code_enum<vkb::QueueError> : true_type {}; template <> struct is_error_code_enum<vkb::QueueError> : true_type {};
template <> struct is_error_code_enum<vkb::DeviceError> : true_type {}; template <> struct is_error_code_enum<vkb::DeviceError> : true_type {};
template <> struct is_error_code_enum<vkb::SwapchainError> : true_type {}; template <> struct is_error_code_enum<vkb::SwapchainError> : true_type {};
template <> struct is_error_code_enum<vkb::PipelineLayoutError> : true_type {};
template <> struct is_error_code_enum<vkb::GraphicsPipelineError> : true_type {};
} // namespace std } // namespace std

386
src/VkPipelineBuilder.h Normal file
View File

@ -0,0 +1,386 @@
/*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the Software), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Copyright © 2020 Charles Giessen (charles@lunarg.com)
*/
#pragma once
#include "VkBootstrap.h"
namespace vkb {
class PipelineLayoutBuilder {
public:
// Construct a PipelineLayoutBuilder with a 'vkb::Device'
explicit PipelineLayoutBuilder(Device const& device);
// Construct a PipelineLayoutBuilder with a specific VkDevice handle
explicit PipelineLayoutBuilder(VkDevice const device);
Result<VkPipelineLayout> build() const;
// Set the bitmask of the pipeline layout creation flags.
PipelineLayoutBuilder& set_pipeline_layout_flags(VkPipelineLayoutCreateFlags layout_flags);
// Add descriptor set layout(s) to the list of descriptor set layouts to be applied to pipeline layout.
PipelineLayoutBuilder& add_descriptor_layout(VkDescriptorSetLayout descriptor_set_layout);
PipelineLayoutBuilder& add_descriptor_layouts(std::vector<VkDescriptorSetLayout> descriptor_set_layouts);
PipelineLayoutBuilder& clear_descriptor_layouts();
// Add push constant range(s) to the list of push constant ranges to be applied to pipeline layout.
PipelineLayoutBuilder& add_push_constant_range(VkPushConstantRange push_constant_range);
PipelineLayoutBuilder& add_push_constant_ranges(std::vector<VkPushConstantRange> push_constant_ranges);
PipelineLayoutBuilder& clear_push_constant_ranges();
// Add a structure to the pNext chain of vkPipelineLayoutCreateInfo.
// The structure must be valid when PipelineLayoutBuilder::build() is called.
template <typename T> PipelineLayoutBuilder& add_pNext(T* structure) {
info.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
PipelineLayoutBuilder& clear_pNext_chain();
// Provide custom allocation callbacks.
PipelineLayoutBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
private:
struct PipelineLayoutInfo {
VkDevice device = VK_NULL_HANDLE;
VkAllocationCallbacks* allocation_callbacks = nullptr;
VkPipelineLayoutCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
std::vector<VkDescriptorSetLayout> descriptor_layouts;
std::vector<VkPushConstantRange> push_constant_ranges;
PFN_vkCreatePipelineLayout pipeline_layout_create_proc = nullptr;
} info;
};
class GraphicsPipelineBuilder {
public:
GraphicsPipelineBuilder(Device const& device, VkPipelineCache pipeline_cache = VK_NULL_HANDLE);
GraphicsPipelineBuilder(VkDevice const device, VkPipelineCache pipeline_cache = VK_NULL_HANDLE);
Result<VkPipeline> build() const;
template <typename T> GraphicsPipelineBuilder& add_pNext(T* structure) {
info.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_pNext();
GraphicsPipelineBuilder& set_pipeline_create_flags(VkPipelineCreateFlags pipeline_create_flags);
GraphicsPipelineBuilder& set_pipeline_layout(VkPipelineLayout pipeline_layout);
GraphicsPipelineBuilder& set_renderpass(VkRenderPass renderpass, uint32_t subpass_index);
GraphicsPipelineBuilder& set_base_pipeline(VkPipeline base_pipeline, uint32_t base_pipeline_index);
GraphicsPipelineBuilder& add_additional_shader_stage(VkPipelineShaderStageCreateInfo& shader_stage_info);
GraphicsPipelineBuilder& add_additional_shader_stages(std::vector<VkPipelineShaderStageCreateInfo> shader_stage_infos);
GraphicsPipelineBuilder& clear_additional_shader_stages();
// Vertex input state
template <typename T> GraphicsPipelineBuilder& add_vertex_input_pNext(T* structure) {
info.vertex_input.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_vertex_input_pNext();
GraphicsPipelineBuilder& add_vertex_input_binding_desc(VkVertexInputBindingDescription vertex_input_binding_desc);
GraphicsPipelineBuilder& add_vertex_input_binding_descs(std::vector<VkVertexInputBindingDescription> vertex_input_binding_descs);
GraphicsPipelineBuilder& clear_vertex_input_binding_descs();
GraphicsPipelineBuilder& add_vertex_input_attrib_desc(VkVertexInputAttributeDescription vertex_input_attrib_desc);
GraphicsPipelineBuilder& add_vertex_input_attrib_descs(std::vector<VkVertexInputAttributeDescription> vertex_input_attrib_descs);
GraphicsPipelineBuilder& clear_vertex_input_attrib_descs();
// Input assembly state
GraphicsPipelineBuilder& set_input_assembly_primitive_topology(VkPrimitiveTopology topology);
GraphicsPipelineBuilder& set_input_assembly_primitive_restart(bool enable_primitive_restart);
// Vertex shader
template <typename T> GraphicsPipelineBuilder& add_vertex_shader_pNext(T* structure) {
info.vertex_shader.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_vertex_shader_pNext();
GraphicsPipelineBuilder& set_vertex_shader_flags(VkPipelineShaderStageCreateFlags flags);
GraphicsPipelineBuilder& set_vertex_shader_module(VkShaderModule shader_module);
GraphicsPipelineBuilder& set_vertex_shader_name(const char* name);
GraphicsPipelineBuilder& set_vertex_shader_specialization_info(VkSpecializationInfo& specialization_info);
GraphicsPipelineBuilder& clear_vertex_shader();
// Tessellation control shader
template <typename T> GraphicsPipelineBuilder& add_tessellation_control_shader_pNext(T* structure) {
info.tessellation_control_shader.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_tessellation_control_shader_pNext();
GraphicsPipelineBuilder& set_tessellation_control_shader_flags(VkPipelineShaderStageCreateFlags flags);
GraphicsPipelineBuilder& set_tessellation_control_shader_module(VkShaderModule shader_module);
GraphicsPipelineBuilder& set_tessellation_control_shader_name(const char* name);
GraphicsPipelineBuilder& set_tessellation_control_shader_specialization_info(VkSpecializationInfo& specialization_info);
GraphicsPipelineBuilder& clear_tessellation_control_shader();
// Tessellation evaluation shader
template <typename T> GraphicsPipelineBuilder& add_tessellation_eval_shader_pNext(T* structure) {
info.tessellation_eval_shader.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_tessellation_eval_shader_pNext();
GraphicsPipelineBuilder& set_tessellation_eval_shader_flags(VkPipelineShaderStageCreateFlags flags);
GraphicsPipelineBuilder& set_tessellation_eval_shader_module(VkShaderModule shader_module);
GraphicsPipelineBuilder& set_tessellation_eval_shader_name(const char* name);
GraphicsPipelineBuilder& set_tessellation_eval_shader_specialization_info(VkSpecializationInfo& specialization_info);
GraphicsPipelineBuilder& clear_tessellation_eval_shader();
// Tessellation state
template <typename T> GraphicsPipelineBuilder& add_tessellation_state_pNext(T* structure) {
info.tessellation_state.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_tessellation_state_pNext();
GraphicsPipelineBuilder& set_tessellation_state_patch_control_points(uint32_t patch_control_points);
// Geometry shader
template <typename T> GraphicsPipelineBuilder& add_geometry_shader_pNext(T* structure) {
info.geometry_shader.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_geometry_shader_pNext();
GraphicsPipelineBuilder& set_geometry_shader_flags(VkPipelineShaderStageCreateFlags flags);
GraphicsPipelineBuilder& set_geometry_shader_module(VkShaderModule shader_module);
GraphicsPipelineBuilder& set_geometry_shader_name(const char* name);
GraphicsPipelineBuilder& set_geometry_shader_specialization_info(VkSpecializationInfo& specialization_info);
GraphicsPipelineBuilder& clear_geometry_shader();
// Viewport state
template <typename T> GraphicsPipelineBuilder& add_viewport_state_pNext(T* structure) {
info.viewport_state.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_viewport_state_pNext();
GraphicsPipelineBuilder& add_viewport_state_viewport(VkViewport viewport);
GraphicsPipelineBuilder& add_viewport_state_viewports(std::vector<VkViewport> viewports);
GraphicsPipelineBuilder& clear_viewport_state_viewports();
GraphicsPipelineBuilder& add_viewport_state_scissor(VkRect2D scissor);
GraphicsPipelineBuilder& add_viewport_state_scissors(std::vector<VkRect2D> scissors);
GraphicsPipelineBuilder& clear_viewport_state_scissors();
// Fragment shader
template <typename T> GraphicsPipelineBuilder& add_fragment_shader_pNext(T* structure) {
info.fragment_shader.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_fragment_shader_pNext();
GraphicsPipelineBuilder& set_fragment_shader_flags(VkPipelineShaderStageCreateFlags flags);
GraphicsPipelineBuilder& set_fragment_shader_module(VkShaderModule shader_module);
GraphicsPipelineBuilder& set_fragment_shader_name(const char* name);
GraphicsPipelineBuilder& set_fragment_shader_specialization_info(VkSpecializationInfo& specialization_info);
GraphicsPipelineBuilder& clear_fragment_shader();
// Rasterization state
template <typename T> GraphicsPipelineBuilder& add_rasterization_state_pNext(T* structure) {
info.rasterization_state.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_rasterization_state_pNext();
GraphicsPipelineBuilder& enable_rasterization_state_depth_clamp(bool enable_depth_clamp);
GraphicsPipelineBuilder& enable_rasterization_state_discard(bool enable_rasterizer_discard);
GraphicsPipelineBuilder& set_rasterization_state_polygon_mode(VkPolygonMode polygon_mode);
GraphicsPipelineBuilder& set_rasterization_state_cull_mode_flags(VkCullModeFlags cull_mode_flags);
GraphicsPipelineBuilder& set_rasterization_state_front_face(VkFrontFace front_face);
GraphicsPipelineBuilder& enable_rasterization_state_depth_bias(bool enable_depth_bias);
GraphicsPipelineBuilder& set_rasterization_state_depth_bias_constant_factor(float depth_bias_constant_factor);
GraphicsPipelineBuilder& set_rasterization_state_depth_bias_clamp(float depth_bias_clamp);
GraphicsPipelineBuilder& set_rasterization_state_depth_bias_slope_factor(float depth_bias_slope_factor);
GraphicsPipelineBuilder& set_rasterization_state_line_width(float line_width);
// Multisample state
template <typename T> GraphicsPipelineBuilder& add_multisample_state_pNext(T* structure) {
info.multisample_state.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_multisample_state_pNext();
GraphicsPipelineBuilder& set_multisample_state_sample_count(VkSampleCountFlagBits sample_count);
GraphicsPipelineBuilder& enable_multisample_state_sample_shading(bool enable_sample_shading);
GraphicsPipelineBuilder& set_multisample_state_min_sample_shading(float min_sample_shading);
GraphicsPipelineBuilder& set_multisample_state_sample_mask(VkSampleMask sample_mask);
GraphicsPipelineBuilder& enable_multisample_state_alpha_to_coverage(bool enable_alpha_to_coverage);
GraphicsPipelineBuilder& enable_multisample_state_alpha_to_one(bool enable_alpha_to_one);
// Depth stencil state
template <typename T> GraphicsPipelineBuilder& add_depth_stencil_state_pNext(T* structure) {
info.depth_stencil_state.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_depth_stencil_state_pNext();
GraphicsPipelineBuilder& set_depth_stencil_state_flags(VkPipelineDepthStencilStateCreateFlags flags);
GraphicsPipelineBuilder& enable_depth_stencil_depth_testing(bool enable_depth_testing);
GraphicsPipelineBuilder& enable_depth_stencil_depth_write(bool enable_depth_write);
GraphicsPipelineBuilder& set_depth_stencil_compare_op(VkCompareOp compare_op);
GraphicsPipelineBuilder& enable_depth_stencil_depth_bounds_test(bool enable_depth_bounds_test);
GraphicsPipelineBuilder& enable_depth_stencil_stencil_test(bool enable_stencil_test);
GraphicsPipelineBuilder& set_depth_stencil_front_stencil_op_state(VkStencilOpState front);
GraphicsPipelineBuilder& set_depth_stencil_back_stencil_op_state(VkStencilOpState back);
GraphicsPipelineBuilder& set_depth_stencil_min_depth_bounds(float min_depth_bounds);
GraphicsPipelineBuilder& set_depth_stencil_max_depth_bounds(float max_depth_bounds);
// Color blend state
template <typename T> GraphicsPipelineBuilder& add_color_blend_state_pNext(T* structure) {
info.color_blend_state.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
GraphicsPipelineBuilder& clear_color_blend_state_pNext();
GraphicsPipelineBuilder& set_color_blend_state_flags(VkPipelineColorBlendStateCreateFlags flags);
GraphicsPipelineBuilder& enable_color_blend_state_logic_op(bool enable_logic_op);
GraphicsPipelineBuilder& set_color_blend_state_logic_op(VkLogicOp logic_op);
GraphicsPipelineBuilder& add_color_blend_state_color_blend_attachment(VkPipelineColorBlendAttachmentState attachment);
GraphicsPipelineBuilder& add_color_blend_state_color_blend_attachments(std::vector<VkPipelineColorBlendAttachmentState> attachments);
GraphicsPipelineBuilder& clear_color_blend_state_color_blend_attachments();
GraphicsPipelineBuilder& set_color_blend_state_blend_constants(float red, float green, float blue, float alpha);
// Dynamic state
GraphicsPipelineBuilder& clear_dynamic_state_pNext();
GraphicsPipelineBuilder& add_dynamic_state(VkDynamicState& dynamic_state);
GraphicsPipelineBuilder& add_dynamic_states(std::vector<VkDynamicState> dynamic_states);
GraphicsPipelineBuilder& clear_dynamic_states();
// Provide custom allocation callbacks.
GraphicsPipelineBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
private:
struct GraphicsPipelineInfo {
VkDevice device = VK_NULL_HANDLE;
VkPipelineCache pipeline_cache = VK_NULL_HANDLE;
VkAllocationCallbacks* allocation_callbacks = nullptr;
VkPipelineCreateFlags flags = 0;
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
VkRenderPass renderpass = VK_NULL_HANDLE;
uint32_t subpass = 0;
VkPipeline base_pipeline = VK_NULL_HANDLE;
uint32_t base_pipeline_index = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
std::vector<VkPipelineShaderStageCreateInfo> additional_shader_stages;
PFN_vkCreateGraphicsPipelines graphics_pipeline_create_proc = nullptr;
struct VertexInput { // Vertex input state
std::vector<VkBaseOutStructure*> pNext_chain;
std::vector<VkVertexInputBindingDescription> binding_descs;
std::vector<VkVertexInputAttributeDescription> attrib_descs;
} vertex_input;
struct InputAssembly { // Input assembly state
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkBool32 primitiveRestartEnable = VK_FALSE;
} input_assembly;
// Vertex shader state
struct VertexShader {
VkPipelineShaderStageCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
VkShaderModule shader_module = VK_NULL_HANDLE;
const char* name = "";
VkSpecializationInfo specialization_info = {};
} vertex_shader;
struct TessellationControlShader { // Tessellation shader stage
VkPipelineShaderStageCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
VkShaderModule shader_module = VK_NULL_HANDLE;
const char* name = "";
VkSpecializationInfo specialization_info = {};
} tessellation_control_shader;
struct TessellationEvaluationShader { // Tessellation shader stage
VkPipelineShaderStageCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
VkShaderModule shader_module = VK_NULL_HANDLE;
const char* name = "";
VkSpecializationInfo specialization_info = {};
} tessellation_eval_shader;
struct TessellationState {
std::vector<VkBaseOutStructure*> pNext_chain;
uint32_t patch_control_points;
} tessellation_state;
struct GeometryShader {
VkPipelineShaderStageCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
VkShaderModule shader_module = VK_NULL_HANDLE;
const char* name = "";
VkSpecializationInfo specialization_info = {};
} geometry_shader;
struct ViewportState { // Viewport state
std::vector<VkBaseOutStructure*> pNext_chain;
std::vector<VkViewport> viewports;
std::vector<VkRect2D> scissors;
} viewport_state;
struct FragmentShader {
VkPipelineShaderStageCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
VkShaderModule shader_module = VK_NULL_HANDLE;
const char* name = "";
VkSpecializationInfo specialization_info = {};
} fragment_shader;
struct RasterizationState { // Rasterization state
std::vector<VkBaseOutStructure*> pNext_chain;
VkBool32 depth_clamp_enable = VK_FALSE;
VkBool32 rasterizer_discard_enable = VK_FALSE;
VkPolygonMode polygon_mode = VK_POLYGON_MODE_FILL;
VkCullModeFlags cull_mode_flags = VK_CULL_MODE_BACK_BIT;
VkFrontFace front_face = VK_FRONT_FACE_COUNTER_CLOCKWISE;
VkBool32 depth_bias_enable = VK_FALSE;
float depth_bias_constant_factor = 0.0f;
float depth_bias_clamp = 0.0f;
float depth_bias_slope_factor = 0.0f;
float line_width = 0.0f;
} rasterization_state;
struct MultisampleState {
std::vector<VkBaseOutStructure*> pNext_chain;
VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_1_BIT;
VkBool32 sample_shading = VK_FALSE;
float min_sample_shading = 0.0f;
VkSampleMask sample_mask = 0;
VkBool32 alpha_to_coverage = VK_FALSE;
VkBool32 alpha_to_one = VK_FALSE;
} multisample_state;
struct DepthStencilState {
std::vector<VkBaseOutStructure*> pNext_chain;
VkPipelineDepthStencilStateCreateFlags flags = 0;
VkBool32 depth_test = VK_FALSE;
VkBool32 depth_write = VK_FALSE;
VkCompareOp depth_compare_operation = VK_COMPARE_OP_GREATER;
VkBool32 depth_bounds_test = VK_FALSE;
VkBool32 stencil_test = VK_FALSE;
VkStencilOpState front_stencil_op_state = {};
VkStencilOpState back_stencil_op_state = {};
float min_depth_bounds = 0.0f;
float max_depth_bounds = 0.0f;
} depth_stencil_state;
struct ColorBlendState {
std::vector<VkBaseOutStructure*> pNext_chain;
VkPipelineColorBlendStateCreateFlags flags = 0;
VkBool32 logic_op_enable = VK_FALSE;
VkLogicOp logic_op = {};
std::vector<VkPipelineColorBlendAttachmentState> attachments;
float blend_constants[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
} color_blend_state;
struct DynamicState {
std::vector<VkDynamicState> dynamic_states;
} dynamic_state;
} info;
};
}; // namespace vkb