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"
@ -13,13 +14,13 @@ const int MAX_FRAMES_IN_FLIGHT = 2;
struct Init { struct Init {
GLFWwindow* window; GLFWwindow* window;
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
vkb::Instance instance; vkb::Instance instance;
VkSurfaceKHR surface; VkSurfaceKHR surface;
vkb::Device device; vkb::Device device;
vkb::Swapchain swapchain; vkb::Swapchain swapchain;
//convenience // convenience
VulkanLibrary* operator->(){ return &vk_lib; } VulkanLibrary* operator->() { return &vk_lib; }
}; };
struct RenderData { struct RenderData {
@ -44,72 +45,72 @@ struct RenderData {
size_t current_frame = 0; size_t current_frame = 0;
}; };
int device_initialization (Init& init) { int device_initialization(Init& init) {
init.window = create_window_glfw ("Vulkan Triangle", true); init.window = create_window_glfw("Vulkan Triangle", true);
vkb::InstanceBuilder instance_builder; vkb::InstanceBuilder instance_builder;
auto instance_ret = instance_builder.use_default_debug_messenger ().request_validation_layers ().build (); auto instance_ret = instance_builder.use_default_debug_messenger().request_validation_layers().build();
if (!instance_ret) { if (!instance_ret) {
std::cout << instance_ret.error ().message () << "\n"; std::cout << instance_ret.error().message() << "\n";
return -1; return -1;
} }
init.instance = instance_ret.value (); init.instance = instance_ret.value();
init.vk_lib.init(init.instance); init.vk_lib.init(init.instance);
init.surface = create_surface_glfw (init.instance, init.window); init.surface = create_surface_glfw(init.instance, init.window);
vkb::PhysicalDeviceSelector phys_device_selector (init.instance); vkb::PhysicalDeviceSelector phys_device_selector(init.instance);
auto phys_device_ret = phys_device_selector.set_surface (init.surface).select (); auto phys_device_ret = phys_device_selector.set_surface(init.surface).select();
if (!phys_device_ret) { if (!phys_device_ret) {
std::cout << phys_device_ret.error ().message () << "\n"; std::cout << phys_device_ret.error().message() << "\n";
return -1; return -1;
} }
vkb::PhysicalDevice physical_device = phys_device_ret.value (); vkb::PhysicalDevice physical_device = phys_device_ret.value();
vkb::DeviceBuilder device_builder{ physical_device }; vkb::DeviceBuilder device_builder{ physical_device };
auto device_ret = device_builder.build (); auto device_ret = device_builder.build();
if (!device_ret) { if (!device_ret) {
std::cout << device_ret.error ().message () << "\n"; std::cout << device_ret.error().message() << "\n";
return -1; return -1;
} }
init.device = device_ret.value (); init.device = device_ret.value();
init.vk_lib.init(init.device); init.vk_lib.init(init.device);
return 0; return 0;
} }
int create_swapchain (Init& init) { int create_swapchain(Init& init) {
vkb::SwapchainBuilder swapchain_builder{ init.device }; vkb::SwapchainBuilder swapchain_builder{ init.device };
auto swap_ret = swapchain_builder.set_old_swapchain (init.swapchain).build (); auto swap_ret = swapchain_builder.set_old_swapchain(init.swapchain).build();
if (!swap_ret) { if (!swap_ret) {
std::cout << swap_ret.error ().message () << " " << swap_ret.vk_result () << "\n"; std::cout << swap_ret.error().message() << " " << swap_ret.vk_result() << "\n";
return -1; return -1;
} }
vkb::destroy_swapchain(init.swapchain); vkb::destroy_swapchain(init.swapchain);
init.swapchain = swap_ret.value (); init.swapchain = swap_ret.value();
return 0; return 0;
} }
int get_queues (Init& init, RenderData& data) { int get_queues(Init& init, RenderData& data) {
auto gq = init.device.get_queue (vkb::QueueType::graphics); auto gq = init.device.get_queue(vkb::QueueType::graphics);
if (!gq.has_value ()) { if (!gq.has_value()) {
std::cout << "failed to get graphics queue: " << gq.error ().message () << "\n"; std::cout << "failed to get graphics queue: " << gq.error().message() << "\n";
return -1; return -1;
} }
data.graphics_queue = gq.value (); data.graphics_queue = gq.value();
auto pq = init.device.get_queue (vkb::QueueType::present); auto pq = init.device.get_queue(vkb::QueueType::present);
if (!pq.has_value ()) { if (!pq.has_value()) {
std::cout << "failed to get present queue: " << pq.error ().message () << "\n"; std::cout << "failed to get present queue: " << pq.error().message() << "\n";
return -1; return -1;
} }
data.present_queue = pq.value (); data.present_queue = pq.value();
return 0; return 0;
} }
int create_render_pass (Init& init, RenderData& data) { int create_render_pass(Init& init, RenderData& data) {
VkAttachmentDescription color_attachment = {}; VkAttachmentDescription color_attachment = {};
color_attachment.format = init.swapchain.image_format; color_attachment.format = init.swapchain.image_format;
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
@ -146,51 +147,69 @@ int create_render_pass (Init& init, RenderData& data) {
render_pass_info.dependencyCount = 1; render_pass_info.dependencyCount = 1;
render_pass_info.pDependencies = &dependency; render_pass_info.pDependencies = &dependency;
if (init->vkCreateRenderPass (init.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) { if (init->vkCreateRenderPass(init.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) {
std::cout << "failed to create render pass\n"; std::cout << "failed to create render pass\n";
return -1; // failed to create render pass! return -1; // failed to create render pass!
} }
return 0; return 0;
} }
std::vector<char> readFile (const std::string& filename) { std::vector<char> readFile(const std::string& filename) {
std::ifstream file (filename, std::ios::ate | std::ios::binary); std::ifstream file(filename, std::ios::ate | std::ios::binary);
if (!file.is_open ()) { if (!file.is_open()) {
throw std::runtime_error ("failed to open file!"); throw std::runtime_error("failed to open file!");
} }
size_t file_size = (size_t)file.tellg (); size_t file_size = (size_t)file.tellg();
std::vector<char> buffer (file_size); std::vector<char> buffer(file_size);
file.seekg (0); file.seekg(0);
file.read (buffer.data (), static_cast<std::streamsize> (file_size)); file.read(buffer.data(), static_cast<std::streamsize>(file_size));
file.close (); file.close();
return buffer; return buffer;
} }
VkShaderModule createShaderModule (Init& init, const std::vector<char>& code) { VkShaderModule createShaderModule(Init& init, const std::vector<char>& code) {
VkShaderModuleCreateInfo create_info = {}; VkShaderModuleCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
create_info.codeSize = code.size (); create_info.codeSize = code.size();
create_info.pCode = reinterpret_cast<const uint32_t*> (code.data ()); create_info.pCode = reinterpret_cast<const uint32_t*>(code.data());
VkShaderModule shaderModule; VkShaderModule shaderModule;
if (init->vkCreateShaderModule (init.device, &create_info, nullptr, &shaderModule) != VK_SUCCESS) { if (init->vkCreateShaderModule(init.device, &create_info, nullptr, &shaderModule) != VK_SUCCESS) {
return VK_NULL_HANDLE; // failed to create shader module return VK_NULL_HANDLE; // failed to create shader module
} }
return shaderModule; return shaderModule;
} }
int create_graphics_pipeline (Init& init, RenderData& data) { 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 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");
VkShaderModule vert_module = createShaderModule (init, vert_code); VkShaderModule vert_module = createShaderModule(init, vert_code);
VkShaderModule frag_module = createShaderModule (init, frag_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) {
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) { if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) {
std::cout << "failed to create shader module\n"; std::cout << "failed to create shader module\n";
return -1; // failed to create shader modules return -1; // failed to create shader modules
@ -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
} }
@ -285,8 +303,8 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
VkPipelineDynamicStateCreateInfo dynamic_info = {}; VkPipelineDynamicStateCreateInfo dynamic_info = {};
dynamic_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamic_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_info.dynamicStateCount = static_cast<uint32_t> (dynamic_states.size ()); dynamic_info.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
dynamic_info.pDynamicStates = dynamic_states.data (); dynamic_info.pDynamicStates = dynamic_states.data();
VkGraphicsPipelineCreateInfo pipeline_info = {}; VkGraphicsPipelineCreateInfo pipeline_info = {};
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
@ -304,24 +322,23 @@ 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
} }
init->vkDestroyShaderModule (init.device, frag_module, nullptr); init->vkDestroyShaderModule(init.device, frag_module, nullptr);
init->vkDestroyShaderModule (init.device, vert_module, nullptr); init->vkDestroyShaderModule(init.device, vert_module, nullptr);
return 0; return 0;
} }
int create_framebuffers (Init& init, RenderData& data) { int create_framebuffers(Init& init, RenderData& data) {
data.swapchain_images = init.swapchain.get_images ().value (); data.swapchain_images = init.swapchain.get_images().value();
data.swapchain_image_views = init.swapchain.get_image_views ().value (); data.swapchain_image_views = init.swapchain.get_image_views().value();
data.framebuffers.resize (data.swapchain_image_views.size ()); data.framebuffers.resize(data.swapchain_image_views.size());
for (size_t i = 0; i < data.swapchain_image_views.size (); i++) { for (size_t i = 0; i < data.swapchain_image_views.size(); i++) {
VkImageView attachments[] = { data.swapchain_image_views[i] }; VkImageView attachments[] = { data.swapchain_image_views[i] };
VkFramebufferCreateInfo framebuffer_info = {}; VkFramebufferCreateInfo framebuffer_info = {};
@ -333,43 +350,43 @@ int create_framebuffers (Init& init, RenderData& data) {
framebuffer_info.height = init.swapchain.extent.height; framebuffer_info.height = init.swapchain.extent.height;
framebuffer_info.layers = 1; framebuffer_info.layers = 1;
if (init->vkCreateFramebuffer (init.device, &framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS) { if (init->vkCreateFramebuffer(init.device, &framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS) {
return -1; // failed to create framebuffer return -1; // failed to create framebuffer
} }
} }
return 0; return 0;
} }
int create_command_pool (Init& init, RenderData& data) { int create_command_pool(Init& init, RenderData& data) {
VkCommandPoolCreateInfo pool_info = {}; VkCommandPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.queueFamilyIndex = init.device.get_queue_index (vkb::QueueType::graphics).value (); pool_info.queueFamilyIndex = init.device.get_queue_index(vkb::QueueType::graphics).value();
if (init->vkCreateCommandPool (init.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) { if (init->vkCreateCommandPool(init.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) {
std::cout << "failed to create command pool\n"; std::cout << "failed to create command pool\n";
return -1; // failed to create command pool return -1; // failed to create command pool
} }
return 0; return 0;
} }
int create_command_buffers (Init& init, RenderData& data) { int create_command_buffers(Init& init, RenderData& data) {
data.command_buffers.resize (data.framebuffers.size ()); data.command_buffers.resize(data.framebuffers.size());
VkCommandBufferAllocateInfo allocInfo = {}; VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = data.command_pool; allocInfo.commandPool = data.command_pool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t)data.command_buffers.size (); allocInfo.commandBufferCount = (uint32_t)data.command_buffers.size();
if (init->vkAllocateCommandBuffers (init.device, &allocInfo, data.command_buffers.data ()) != VK_SUCCESS) { if (init->vkAllocateCommandBuffers(init.device, &allocInfo, data.command_buffers.data()) != VK_SUCCESS) {
return -1; // failed to allocate command buffers; return -1; // failed to allocate command buffers;
} }
for (size_t i = 0; i < data.command_buffers.size (); i++) { for (size_t i = 0; i < data.command_buffers.size(); i++) {
VkCommandBufferBeginInfo begin_info = {}; VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
if (init->vkBeginCommandBuffer (data.command_buffers[i], &begin_info) != VK_SUCCESS) { if (init->vkBeginCommandBuffer(data.command_buffers[i], &begin_info) != VK_SUCCESS) {
return -1; // failed to begin recording command buffer return -1; // failed to begin recording command buffer
} }
@ -395,18 +412,18 @@ int create_command_buffers (Init& init, RenderData& data) {
scissor.offset = { 0, 0 }; scissor.offset = { 0, 0 };
scissor.extent = init.swapchain.extent; scissor.extent = init.swapchain.extent;
init->vkCmdSetViewport (data.command_buffers[i], 0, 1, &viewport); init->vkCmdSetViewport(data.command_buffers[i], 0, 1, &viewport);
init->vkCmdSetScissor (data.command_buffers[i], 0, 1, &scissor); init->vkCmdSetScissor(data.command_buffers[i], 0, 1, &scissor);
init->vkCmdBeginRenderPass (data.command_buffers[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); init->vkCmdBeginRenderPass(data.command_buffers[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
init->vkCmdBindPipeline (data.command_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphics_pipeline); init->vkCmdBindPipeline(data.command_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphics_pipeline);
init->vkCmdDraw (data.command_buffers[i], 3, 1, 0, 0); init->vkCmdDraw(data.command_buffers[i], 3, 1, 0, 0);
init->vkCmdEndRenderPass (data.command_buffers[i]); init->vkCmdEndRenderPass(data.command_buffers[i]);
if (init->vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS) { if (init->vkEndCommandBuffer(data.command_buffers[i]) != VK_SUCCESS) {
std::cout << "failed to record command buffer\n"; std::cout << "failed to record command buffer\n";
return -1; // failed to record command buffer! return -1; // failed to record command buffer!
} }
@ -414,11 +431,11 @@ int create_command_buffers (Init& init, RenderData& data) {
return 0; return 0;
} }
int create_sync_objects (Init& init, RenderData& data) { int create_sync_objects(Init& init, RenderData& data) {
data.available_semaphores.resize (MAX_FRAMES_IN_FLIGHT); data.available_semaphores.resize(MAX_FRAMES_IN_FLIGHT);
data.finished_semaphore.resize (MAX_FRAMES_IN_FLIGHT); data.finished_semaphore.resize(MAX_FRAMES_IN_FLIGHT);
data.in_flight_fences.resize (MAX_FRAMES_IN_FLIGHT); data.in_flight_fences.resize(MAX_FRAMES_IN_FLIGHT);
data.image_in_flight.resize (init.swapchain.image_count, VK_NULL_HANDLE); data.image_in_flight.resize(init.swapchain.image_count, VK_NULL_HANDLE);
VkSemaphoreCreateInfo semaphore_info = {}; VkSemaphoreCreateInfo semaphore_info = {};
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@ -428,9 +445,9 @@ int create_sync_objects (Init& init, RenderData& data) {
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
if (init->vkCreateSemaphore (init.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS || if (init->vkCreateSemaphore(init.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS ||
init->vkCreateSemaphore (init.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS || init->vkCreateSemaphore(init.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS ||
init->vkCreateFence (init.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) { init->vkCreateFence(init.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) {
std::cout << "failed to create sync objects\n"; std::cout << "failed to create sync objects\n";
return -1; // failed to create synchronization objects for a frame return -1; // failed to create synchronization objects for a frame
} }
@ -438,44 +455,40 @@ int create_sync_objects (Init& init, RenderData& data) {
return 0; return 0;
} }
int recreate_swapchain (Init& init, RenderData& data) { int recreate_swapchain(Init& init, RenderData& data) {
init->vkDeviceWaitIdle (init.device); init->vkDeviceWaitIdle(init.device);
init->vkDestroyCommandPool (init.device, data.command_pool, nullptr); init->vkDestroyCommandPool(init.device, data.command_pool, nullptr);
for (auto framebuffer : data.framebuffers) { for (auto framebuffer : data.framebuffers) {
init->vkDestroyFramebuffer (init.device, framebuffer, nullptr); init->vkDestroyFramebuffer(init.device, framebuffer, nullptr);
} }
init.swapchain.destroy_image_views (data.swapchain_image_views); init.swapchain.destroy_image_views(data.swapchain_image_views);
if (0 != create_swapchain (init)) return -1; if (0 != create_swapchain(init)) return -1;
if (0 != create_framebuffers (init, data)) return -1; if (0 != create_framebuffers(init, data)) return -1;
if (0 != create_command_pool (init, data)) return -1; if (0 != create_command_pool(init, data)) return -1;
if (0 != create_command_buffers (init, data)) return -1; if (0 != create_command_buffers(init, data)) return -1;
return 0; return 0;
} }
int draw_frame (Init& init, RenderData& data) { 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);
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
std::cout << "failed to acquire swapchain image. Error " << result << "\n"; std::cout << "failed to acquire swapchain image. Error " << result << "\n";
return -1; return -1;
} }
if (data.image_in_flight[image_index] != VK_NULL_HANDLE) { if (data.image_in_flight[image_index] != VK_NULL_HANDLE) {
init->vkWaitForFences (init.device, 1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX); init->vkWaitForFences(init.device, 1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX);
} }
data.image_in_flight[image_index] = data.in_flight_fences[data.current_frame]; data.image_in_flight[image_index] = data.in_flight_fences[data.current_frame];
@ -495,9 +508,9 @@ int draw_frame (Init& init, RenderData& data) {
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signal_semaphores; submitInfo.pSignalSemaphores = signal_semaphores;
init->vkResetFences (init.device, 1, &data.in_flight_fences[data.current_frame]); init->vkResetFences(init.device, 1, &data.in_flight_fences[data.current_frame]);
if (init->vkQueueSubmit (data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) { if (init->vkQueueSubmit(data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) {
std::cout << "failed to submit draw command buffer\n"; std::cout << "failed to submit draw command buffer\n";
return -1; //"failed to submit draw command buffer return -1; //"failed to submit draw command buffer
} }
@ -514,9 +527,9 @@ int draw_frame (Init& init, RenderData& data) {
present_info.pImageIndices = &image_index; present_info.pImageIndices = &image_index;
result = init->vkQueuePresentKHR (data.present_queue, &present_info); result = init->vkQueuePresentKHR(data.present_queue, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
return recreate_swapchain (init, data); return recreate_swapchain(init, data);
} else if (result != VK_SUCCESS) { } else if (result != VK_SUCCESS) {
std::cout << "failed to present swapchain image\n"; std::cout << "failed to present swapchain image\n";
return -1; return -1;
@ -526,56 +539,56 @@ int draw_frame (Init& init, RenderData& data) {
return 0; return 0;
} }
void cleanup (Init& init, RenderData& data) { void cleanup(Init& init, RenderData& data) {
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
init->vkDestroySemaphore (init.device, data.finished_semaphore[i], nullptr); init->vkDestroySemaphore(init.device, data.finished_semaphore[i], nullptr);
init->vkDestroySemaphore (init.device, data.available_semaphores[i], nullptr); init->vkDestroySemaphore(init.device, data.available_semaphores[i], nullptr);
init->vkDestroyFence (init.device, data.in_flight_fences[i], nullptr); init->vkDestroyFence(init.device, data.in_flight_fences[i], nullptr);
} }
init->vkDestroyCommandPool (init.device, data.command_pool, nullptr); init->vkDestroyCommandPool(init.device, data.command_pool, nullptr);
for (auto framebuffer : data.framebuffers) { for (auto framebuffer : data.framebuffers) {
init->vkDestroyFramebuffer (init.device, framebuffer, nullptr); init->vkDestroyFramebuffer(init.device, framebuffer, nullptr);
} }
init->vkDestroyPipeline (init.device, data.graphics_pipeline, nullptr); init->vkDestroyPipeline(init.device, data.graphics_pipeline, nullptr);
init->vkDestroyPipelineLayout (init.device, data.pipeline_layout, nullptr); init->vkDestroyPipelineLayout(init.device, data.pipeline_layout, nullptr);
init->vkDestroyRenderPass (init.device, data.render_pass, nullptr); init->vkDestroyRenderPass(init.device, data.render_pass, nullptr);
init.swapchain.destroy_image_views (data.swapchain_image_views); init.swapchain.destroy_image_views(data.swapchain_image_views);
vkb::destroy_swapchain (init.swapchain); vkb::destroy_swapchain(init.swapchain);
vkb::destroy_device (init.device); vkb::destroy_device(init.device);
vkb::destroy_surface(init.instance, init.surface); vkb::destroy_surface(init.instance, init.surface);
vkb::destroy_instance (init.instance); vkb::destroy_instance(init.instance);
destroy_window_glfw (init.window); destroy_window_glfw(init.window);
} }
int main () { int main() {
Init init; Init init;
RenderData render_data; RenderData render_data;
if (0 != device_initialization (init)) return -1; if (0 != device_initialization(init)) return -1;
if (0 != create_swapchain (init)) return -1; if (0 != create_swapchain(init)) return -1;
if (0 != get_queues (init, render_data)) return -1; if (0 != get_queues(init, render_data)) return -1;
if (0 != create_render_pass (init, render_data)) return -1; if (0 != create_render_pass(init, render_data)) return -1;
if (0 != create_graphics_pipeline (init, render_data)) return -1; if (0 != create_graphics_pipeline(init, render_data)) return -1;
if (0 != create_framebuffers (init, render_data)) return -1; if (0 != create_framebuffers(init, render_data)) return -1;
if (0 != create_command_pool (init, render_data)) return -1; if (0 != create_command_pool(init, render_data)) return -1;
if (0 != create_command_buffers (init, render_data)) return -1; if (0 != create_command_buffers(init, render_data)) return -1;
if (0 != create_sync_objects (init, render_data)) return -1; if (0 != create_sync_objects(init, render_data)) return -1;
while (!glfwWindowShouldClose (init.window)) { while (!glfwWindowShouldClose(init.window)) {
glfwPollEvents (); glfwPollEvents();
int res = draw_frame (init, render_data); int res = draw_frame(init, render_data);
if (res != 0) { if (res != 0) {
std::cout << "failed to draw frame \n"; std::cout << "failed to draw frame \n";
return -1; return -1;
} }
} }
init->vkDeviceWaitIdle (init.device); init->vkDeviceWaitIdle(init.device);
cleanup (init, render_data); cleanup(init, render_data);
return 0; return 0;
} }

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