mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-22 07: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 "../tests/common.h"
|
||||
#include "VkPipelineBuilder.h"
|
||||
|
||||
#include "example_config.h"
|
||||
|
||||
@ -13,13 +14,13 @@ const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||
|
||||
struct Init {
|
||||
GLFWwindow* window;
|
||||
VulkanLibrary vk_lib;
|
||||
VulkanLibrary vk_lib;
|
||||
vkb::Instance instance;
|
||||
VkSurfaceKHR surface;
|
||||
vkb::Device device;
|
||||
vkb::Swapchain swapchain;
|
||||
//convenience
|
||||
VulkanLibrary* operator->(){ return &vk_lib; }
|
||||
// convenience
|
||||
VulkanLibrary* operator->() { return &vk_lib; }
|
||||
};
|
||||
|
||||
struct RenderData {
|
||||
@ -44,72 +45,72 @@ struct RenderData {
|
||||
size_t current_frame = 0;
|
||||
};
|
||||
|
||||
int device_initialization (Init& init) {
|
||||
init.window = create_window_glfw ("Vulkan Triangle", true);
|
||||
int device_initialization(Init& init) {
|
||||
init.window = create_window_glfw("Vulkan Triangle", true);
|
||||
|
||||
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) {
|
||||
std::cout << instance_ret.error ().message () << "\n";
|
||||
std::cout << instance_ret.error().message() << "\n";
|
||||
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);
|
||||
auto phys_device_ret = phys_device_selector.set_surface (init.surface).select ();
|
||||
vkb::PhysicalDeviceSelector phys_device_selector(init.instance);
|
||||
auto phys_device_ret = phys_device_selector.set_surface(init.surface).select();
|
||||
if (!phys_device_ret) {
|
||||
std::cout << phys_device_ret.error ().message () << "\n";
|
||||
std::cout << phys_device_ret.error().message() << "\n";
|
||||
return -1;
|
||||
}
|
||||
vkb::PhysicalDevice physical_device = phys_device_ret.value ();
|
||||
vkb::PhysicalDevice physical_device = phys_device_ret.value();
|
||||
|
||||
vkb::DeviceBuilder device_builder{ physical_device };
|
||||
auto device_ret = device_builder.build ();
|
||||
auto device_ret = device_builder.build();
|
||||
if (!device_ret) {
|
||||
std::cout << device_ret.error ().message () << "\n";
|
||||
std::cout << device_ret.error().message() << "\n";
|
||||
return -1;
|
||||
}
|
||||
init.device = device_ret.value ();
|
||||
init.vk_lib.init(init.device);
|
||||
init.device = device_ret.value();
|
||||
init.vk_lib.init(init.device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_swapchain (Init& init) {
|
||||
int create_swapchain(Init& init) {
|
||||
|
||||
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) {
|
||||
std::cout << swap_ret.error ().message () << " " << swap_ret.vk_result () << "\n";
|
||||
return -1;
|
||||
std::cout << swap_ret.error().message() << " " << swap_ret.vk_result() << "\n";
|
||||
return -1;
|
||||
}
|
||||
vkb::destroy_swapchain(init.swapchain);
|
||||
init.swapchain = swap_ret.value ();
|
||||
vkb::destroy_swapchain(init.swapchain);
|
||||
init.swapchain = swap_ret.value();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_queues (Init& init, RenderData& data) {
|
||||
auto gq = init.device.get_queue (vkb::QueueType::graphics);
|
||||
if (!gq.has_value ()) {
|
||||
std::cout << "failed to get graphics queue: " << gq.error ().message () << "\n";
|
||||
int get_queues(Init& init, RenderData& data) {
|
||||
auto gq = init.device.get_queue(vkb::QueueType::graphics);
|
||||
if (!gq.has_value()) {
|
||||
std::cout << "failed to get graphics queue: " << gq.error().message() << "\n";
|
||||
return -1;
|
||||
}
|
||||
data.graphics_queue = gq.value ();
|
||||
data.graphics_queue = gq.value();
|
||||
|
||||
auto pq = init.device.get_queue (vkb::QueueType::present);
|
||||
if (!pq.has_value ()) {
|
||||
std::cout << "failed to get present queue: " << pq.error ().message () << "\n";
|
||||
auto pq = init.device.get_queue(vkb::QueueType::present);
|
||||
if (!pq.has_value()) {
|
||||
std::cout << "failed to get present queue: " << pq.error().message() << "\n";
|
||||
return -1;
|
||||
}
|
||||
data.present_queue = pq.value ();
|
||||
data.present_queue = pq.value();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_render_pass (Init& init, RenderData& data) {
|
||||
int create_render_pass(Init& init, RenderData& data) {
|
||||
VkAttachmentDescription color_attachment = {};
|
||||
color_attachment.format = init.swapchain.image_format;
|
||||
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.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";
|
||||
return -1; // failed to create render pass!
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<char> readFile (const std::string& filename) {
|
||||
std::ifstream file (filename, std::ios::ate | std::ios::binary);
|
||||
std::vector<char> readFile(const std::string& filename) {
|
||||
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||
|
||||
if (!file.is_open ()) {
|
||||
throw std::runtime_error ("failed to open file!");
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("failed to open file!");
|
||||
}
|
||||
|
||||
size_t file_size = (size_t)file.tellg ();
|
||||
std::vector<char> buffer (file_size);
|
||||
size_t file_size = (size_t)file.tellg();
|
||||
std::vector<char> buffer(file_size);
|
||||
|
||||
file.seekg (0);
|
||||
file.read (buffer.data (), static_cast<std::streamsize> (file_size));
|
||||
file.seekg(0);
|
||||
file.read(buffer.data(), static_cast<std::streamsize>(file_size));
|
||||
|
||||
file.close ();
|
||||
file.close();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
VkShaderModule createShaderModule (Init& init, const std::vector<char>& code) {
|
||||
VkShaderModule createShaderModule(Init& init, const std::vector<char>& code) {
|
||||
VkShaderModuleCreateInfo create_info = {};
|
||||
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
create_info.codeSize = code.size ();
|
||||
create_info.pCode = reinterpret_cast<const uint32_t*> (code.data ());
|
||||
create_info.codeSize = code.size();
|
||||
create_info.pCode = reinterpret_cast<const uint32_t*>(code.data());
|
||||
|
||||
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 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 frag_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/frag.spv");
|
||||
|
||||
VkShaderModule vert_module = createShaderModule (init, vert_code);
|
||||
VkShaderModule frag_module = createShaderModule (init, frag_code);
|
||||
VkShaderModule vert_module = createShaderModule(init, vert_code);
|
||||
VkShaderModule frag_module = createShaderModule(init, frag_code);
|
||||
if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) {
|
||||
std::cout << "failed to create shader module\n";
|
||||
return -1; // failed to create shader modules
|
||||
}
|
||||
|
||||
gpb.set_vertex_shader_entrypoint_name()
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_graphics_pipeline(Init& init, RenderData& data) {
|
||||
auto vert_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/vert.spv");
|
||||
auto frag_code = readFile(std::string(EXAMPLE_BUILD_DIRECTORY) + "/frag.spv");
|
||||
|
||||
VkShaderModule vert_module = createShaderModule(init, vert_code);
|
||||
VkShaderModule frag_module = createShaderModule(init, frag_code);
|
||||
if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) {
|
||||
std::cout << "failed to create shader module\n";
|
||||
return -1; // failed to create shader modules
|
||||
@ -255,8 +274,8 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
|
||||
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
colorBlendAttachment.colorWriteMask =
|
||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
colorBlendAttachment.blendEnable = VK_FALSE;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo color_blending = {};
|
||||
@ -275,8 +294,7 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
|
||||
pipeline_layout_info.setLayoutCount = 0;
|
||||
pipeline_layout_info.pushConstantRangeCount = 0;
|
||||
|
||||
if (init->vkCreatePipelineLayout (
|
||||
init.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) {
|
||||
if (init->vkCreatePipelineLayout(init.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) {
|
||||
std::cout << "failed to create pipeline layout\n";
|
||||
return -1; // failed to create pipeline layout
|
||||
}
|
||||
@ -285,8 +303,8 @@ int create_graphics_pipeline (Init& init, RenderData& data) {
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamic_info = {};
|
||||
dynamic_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamic_info.dynamicStateCount = static_cast<uint32_t> (dynamic_states.size ());
|
||||
dynamic_info.pDynamicStates = dynamic_states.data ();
|
||||
dynamic_info.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
|
||||
dynamic_info.pDynamicStates = dynamic_states.data();
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipeline_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.basePipelineHandle = VK_NULL_HANDLE;
|
||||
|
||||
if (init->vkCreateGraphicsPipelines (
|
||||
init.device, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &data.graphics_pipeline) != VK_SUCCESS) {
|
||||
if (init->vkCreateGraphicsPipelines(init.device, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &data.graphics_pipeline) != VK_SUCCESS) {
|
||||
std::cout << "failed to create pipline\n";
|
||||
return -1; // failed to create graphics pipeline
|
||||
}
|
||||
|
||||
init->vkDestroyShaderModule (init.device, frag_module, nullptr);
|
||||
init->vkDestroyShaderModule (init.device, vert_module, nullptr);
|
||||
init->vkDestroyShaderModule(init.device, frag_module, nullptr);
|
||||
init->vkDestroyShaderModule(init.device, vert_module, nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_framebuffers (Init& init, RenderData& data) {
|
||||
data.swapchain_images = init.swapchain.get_images ().value ();
|
||||
data.swapchain_image_views = init.swapchain.get_image_views ().value ();
|
||||
int create_framebuffers(Init& init, RenderData& data) {
|
||||
data.swapchain_images = init.swapchain.get_images().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] };
|
||||
|
||||
VkFramebufferCreateInfo framebuffer_info = {};
|
||||
@ -333,43 +350,43 @@ int create_framebuffers (Init& init, RenderData& data) {
|
||||
framebuffer_info.height = init.swapchain.extent.height;
|
||||
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 0;
|
||||
}
|
||||
|
||||
int create_command_pool (Init& init, RenderData& data) {
|
||||
int create_command_pool(Init& init, RenderData& data) {
|
||||
VkCommandPoolCreateInfo pool_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";
|
||||
return -1; // failed to create command pool
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_command_buffers (Init& init, RenderData& data) {
|
||||
data.command_buffers.resize (data.framebuffers.size ());
|
||||
int create_command_buffers(Init& init, RenderData& data) {
|
||||
data.command_buffers.resize(data.framebuffers.size());
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.commandPool = data.command_pool;
|
||||
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;
|
||||
}
|
||||
|
||||
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 = {};
|
||||
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
|
||||
}
|
||||
|
||||
@ -395,18 +412,18 @@ int create_command_buffers (Init& init, RenderData& data) {
|
||||
scissor.offset = { 0, 0 };
|
||||
scissor.extent = init.swapchain.extent;
|
||||
|
||||
init->vkCmdSetViewport (data.command_buffers[i], 0, 1, &viewport);
|
||||
init->vkCmdSetScissor (data.command_buffers[i], 0, 1, &scissor);
|
||||
init->vkCmdSetViewport(data.command_buffers[i], 0, 1, &viewport);
|
||||
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";
|
||||
return -1; // failed to record command buffer!
|
||||
}
|
||||
@ -414,11 +431,11 @@ int create_command_buffers (Init& init, RenderData& data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_sync_objects (Init& init, RenderData& data) {
|
||||
data.available_semaphores.resize (MAX_FRAMES_IN_FLIGHT);
|
||||
data.finished_semaphore.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);
|
||||
int create_sync_objects(Init& init, RenderData& data) {
|
||||
data.available_semaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
data.finished_semaphore.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);
|
||||
|
||||
VkSemaphoreCreateInfo semaphore_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;
|
||||
|
||||
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 ||
|
||||
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) {
|
||||
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->vkCreateFence(init.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) {
|
||||
std::cout << "failed to create sync objects\n";
|
||||
return -1; // failed to create synchronization objects for a frame
|
||||
}
|
||||
@ -438,44 +455,40 @@ int create_sync_objects (Init& init, RenderData& data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int recreate_swapchain (Init& init, RenderData& data) {
|
||||
init->vkDeviceWaitIdle (init.device);
|
||||
int recreate_swapchain(Init& init, RenderData& data) {
|
||||
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) {
|
||||
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_framebuffers (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_swapchain(init)) return -1;
|
||||
if (0 != create_framebuffers(init, data)) return -1;
|
||||
if (0 != create_command_pool(init, data)) return -1;
|
||||
if (0 != create_command_buffers(init, data)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int draw_frame (Init& init, RenderData& data) {
|
||||
init->vkWaitForFences (init.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX);
|
||||
int draw_frame(Init& init, RenderData& data) {
|
||||
init->vkWaitForFences(init.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
uint32_t image_index = 0;
|
||||
VkResult result = init->vkAcquireNextImageKHR (init.device,
|
||||
init.swapchain,
|
||||
UINT64_MAX,
|
||||
data.available_semaphores[data.current_frame],
|
||||
VK_NULL_HANDLE,
|
||||
&image_index);
|
||||
VkResult result = init->vkAcquireNextImageKHR(
|
||||
init.device, init.swapchain, UINT64_MAX, data.available_semaphores[data.current_frame], VK_NULL_HANDLE, &image_index);
|
||||
|
||||
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) {
|
||||
std::cout << "failed to acquire swapchain image. Error " << result << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
@ -495,9 +508,9 @@ int draw_frame (Init& init, RenderData& data) {
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
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";
|
||||
return -1; //"failed to submit draw command buffer
|
||||
}
|
||||
@ -514,9 +527,9 @@ int draw_frame (Init& init, RenderData& data) {
|
||||
|
||||
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) {
|
||||
return recreate_swapchain (init, data);
|
||||
return recreate_swapchain(init, data);
|
||||
} else if (result != VK_SUCCESS) {
|
||||
std::cout << "failed to present swapchain image\n";
|
||||
return -1;
|
||||
@ -526,56 +539,56 @@ int draw_frame (Init& init, RenderData& data) {
|
||||
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++) {
|
||||
init->vkDestroySemaphore (init.device, data.finished_semaphore[i], nullptr);
|
||||
init->vkDestroySemaphore (init.device, data.available_semaphores[i], nullptr);
|
||||
init->vkDestroyFence (init.device, data.in_flight_fences[i], nullptr);
|
||||
init->vkDestroySemaphore(init.device, data.finished_semaphore[i], nullptr);
|
||||
init->vkDestroySemaphore(init.device, data.available_semaphores[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) {
|
||||
init->vkDestroyFramebuffer (init.device, framebuffer, nullptr);
|
||||
init->vkDestroyFramebuffer(init.device, framebuffer, nullptr);
|
||||
}
|
||||
|
||||
init->vkDestroyPipeline (init.device, data.graphics_pipeline, nullptr);
|
||||
init->vkDestroyPipelineLayout (init.device, data.pipeline_layout, nullptr);
|
||||
init->vkDestroyRenderPass (init.device, data.render_pass, nullptr);
|
||||
init->vkDestroyPipeline(init.device, data.graphics_pipeline, nullptr);
|
||||
init->vkDestroyPipelineLayout(init.device, data.pipeline_layout, 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_device (init.device);
|
||||
vkb::destroy_surface(init.instance, init.surface);
|
||||
vkb::destroy_instance (init.instance);
|
||||
destroy_window_glfw (init.window);
|
||||
vkb::destroy_swapchain(init.swapchain);
|
||||
vkb::destroy_device(init.device);
|
||||
vkb::destroy_surface(init.instance, init.surface);
|
||||
vkb::destroy_instance(init.instance);
|
||||
destroy_window_glfw(init.window);
|
||||
}
|
||||
|
||||
int main () {
|
||||
int main() {
|
||||
Init init;
|
||||
RenderData render_data;
|
||||
|
||||
if (0 != device_initialization (init)) return -1;
|
||||
if (0 != create_swapchain (init)) return -1;
|
||||
if (0 != get_queues (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_framebuffers (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_sync_objects (init, render_data)) return -1;
|
||||
if (0 != device_initialization(init)) return -1;
|
||||
if (0 != create_swapchain(init)) return -1;
|
||||
if (0 != get_queues(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_framebuffers(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_sync_objects(init, render_data)) return -1;
|
||||
|
||||
while (!glfwWindowShouldClose (init.window)) {
|
||||
glfwPollEvents ();
|
||||
int res = draw_frame (init, render_data);
|
||||
while (!glfwWindowShouldClose(init.window)) {
|
||||
glfwPollEvents();
|
||||
int res = draw_frame(init, render_data);
|
||||
if (res != 0) {
|
||||
std::cout << "failed to draw frame \n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
init->vkDeviceWaitIdle (init.device);
|
||||
init->vkDeviceWaitIdle(init.device);
|
||||
|
||||
cleanup (init, render_data);
|
||||
cleanup(init, render_data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "VkBootstrap.h"
|
||||
#include "VkPipelineBuilder.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@ -365,11 +366,23 @@ struct DeviceErrorCategory : std::error_category {
|
||||
const DeviceErrorCategory device_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)); }
|
||||
};
|
||||
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
|
||||
|
||||
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) {
|
||||
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) \
|
||||
case CATEGORY::TYPE: \
|
||||
return #TYPE;
|
||||
@ -446,6 +466,26 @@ const char* to_string(SwapchainError err) {
|
||||
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() {
|
||||
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_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
|
||||
|
@ -214,12 +214,22 @@ enum class SwapchainError {
|
||||
failed_create_swapchain_image_views,
|
||||
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(PhysicalDeviceError physical_device_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(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_type(VkDebugUtilsMessageTypeFlagsEXT s);
|
||||
@ -229,6 +239,8 @@ const char* to_string(PhysicalDeviceError err);
|
||||
const char* to_string(QueueError err);
|
||||
const char* to_string(DeviceError 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
|
||||
// extensions. Use this for enabling features conditionally, ie if you would like an extension but
|
||||
@ -938,8 +950,7 @@ class SwapchainBuilder {
|
||||
} info;
|
||||
};
|
||||
|
||||
} // namespace vkb
|
||||
|
||||
}; // namespace vkb
|
||||
|
||||
namespace std {
|
||||
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::DeviceError> : 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
|
||||
|
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