mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-22 15:24:34 +00:00
Added builders for pipeline layouts and graphics pipelines.
This commit is contained in:
parent
c16de53814
commit
a8248e829b
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
386
src/VkPipelineBuilder.h
Normal 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
|
Loading…
Reference in New Issue
Block a user