Created
September 25, 2020 21:18
-
-
Save seanbaxter/0892819568ed9d2945378b7b3095b658 to your computer and use it in GitHub Desktop.
single-source vulkan triangle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <memory> | |
#include <iostream> | |
#include <fstream> | |
#include <vulkan/common.h> | |
// Shader interface helper variables. | |
template<auto index, typename type_t = @enum_type(index)> | |
[[using spirv: in, location((int)index)]] | |
type_t shader_in; | |
template<auto index, typename type_t = @enum_type(index)> | |
[[using spirv: out, location((int)index)]] | |
type_t shader_out; | |
[[spirv::vert]] | |
void vert_main() { | |
const vec2 positions[3] { | |
0.0, -0.5, | |
0.5, 0.5, | |
-0.5, 0.5, | |
}; | |
const vec3 colors[3] { | |
1, 0, 0, | |
0, 1, 0, | |
0, 0, 1, | |
}; | |
glvert_Output.Position = vec4(positions[glvert_VertexIndex], 0, 1); | |
shader_out<0, vec3> = colors[glvert_VertexIndex]; | |
} | |
[[spirv::frag]] | |
void frag_main() { | |
shader_out<0, vec4> = vec4(shader_in<0, vec3>, 1); | |
} | |
const int MAX_FRAMES_IN_FLIGHT = 2; | |
struct Init { | |
GLFWwindow* window; | |
vkb::Instance instance; | |
VkSurfaceKHR surface; | |
vkb::Device device; | |
vkb::Swapchain swapchain; | |
}; | |
struct RenderData { | |
VkQueue graphics_queue; | |
VkQueue present_queue; | |
std::vector<VkImage> swapchain_images; | |
std::vector<VkImageView> swapchain_image_views; | |
std::vector<VkFramebuffer> framebuffers; | |
VkRenderPass render_pass; | |
VkPipelineLayout pipeline_layout; | |
VkPipeline graphics_pipeline; | |
VkCommandPool command_pool; | |
std::vector<VkCommandBuffer> command_buffers; | |
std::vector<VkSemaphore> available_semaphores; | |
std::vector<VkSemaphore> finished_semaphore; | |
std::vector<VkFence> in_flight_fences; | |
std::vector<VkFence> image_in_flight; | |
size_t current_frame = 0; | |
}; | |
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 (); | |
if (!instance_ret) { | |
std::cout << instance_ret.error ().message () << "\n"; | |
return -1; | |
} | |
init.instance = instance_ret.value (); | |
init.surface = create_surface_glfw (init.instance.instance, init.window); | |
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"; | |
return -1; | |
} | |
vkb::PhysicalDevice physical_device = phys_device_ret.value (); | |
vkb::DeviceBuilder device_builder{ physical_device }; | |
auto device_ret = device_builder.build (); | |
if (!device_ret) { | |
std::cout << device_ret.error ().message () << "\n"; | |
return -1; | |
} | |
init.device = device_ret.value (); | |
return 0; | |
} | |
int create_swapchain (Init& init) { | |
vkb::SwapchainBuilder swapchain_builder{ init.device }; | |
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; | |
} | |
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"; | |
return -1; | |
} | |
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"; | |
return -1; | |
} | |
data.present_queue = pq.value (); | |
return 0; | |
} | |
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; | |
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | |
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; | |
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | |
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | |
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | |
VkAttachmentReference color_attachment_ref = {}; | |
color_attachment_ref.attachment = 0; | |
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
VkSubpassDescription subpass = {}; | |
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; | |
subpass.colorAttachmentCount = 1; | |
subpass.pColorAttachments = &color_attachment_ref; | |
VkSubpassDependency dependency = {}; | |
dependency.srcSubpass = VK_SUBPASS_EXTERNAL; | |
dependency.dstSubpass = 0; | |
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | |
dependency.srcAccessMask = 0; | |
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | |
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | |
VkRenderPassCreateInfo render_pass_info = {}; | |
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; | |
render_pass_info.attachmentCount = 1; | |
render_pass_info.pAttachments = &color_attachment; | |
render_pass_info.subpassCount = 1; | |
render_pass_info.pSubpasses = &subpass; | |
render_pass_info.dependencyCount = 1; | |
render_pass_info.pDependencies = &dependency; | |
if (vkCreateRenderPass (init.device.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); | |
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); | |
file.seekg (0); | |
file.read (buffer.data (), static_cast<std::streamsize> (file_size)); | |
file.close (); | |
return buffer; | |
} | |
VkShaderModule createShaderModule (Init& init) { | |
VkShaderModuleCreateInfo create_info = {}; | |
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; | |
create_info.codeSize = __spirv_size; | |
create_info.pCode = (const uint32_t*)__spirv_data; | |
VkShaderModule shaderModule; | |
if (vkCreateShaderModule (init.device.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) { | |
VkShaderModule module = createShaderModule (init); | |
if (module == VK_NULL_HANDLE) { | |
std::cout << "failed to create shader module\n"; | |
return -1; // failed to create shader modules | |
} | |
VkPipelineShaderStageCreateInfo vert_stage_info = {}; | |
vert_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | |
vert_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; | |
vert_stage_info.module = module; | |
vert_stage_info.pName = @spirv(vert_main); | |
VkPipelineShaderStageCreateInfo frag_stage_info = {}; | |
frag_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | |
frag_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; | |
frag_stage_info.module = module; | |
frag_stage_info.pName = @spirv(frag_main); | |
VkPipelineShaderStageCreateInfo shader_stages[] = { vert_stage_info, frag_stage_info }; | |
VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; | |
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; | |
vertex_input_info.vertexBindingDescriptionCount = 0; | |
vertex_input_info.vertexAttributeDescriptionCount = 0; | |
VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; | |
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; | |
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; | |
input_assembly.primitiveRestartEnable = VK_FALSE; | |
VkViewport viewport = {}; | |
viewport.x = 0.0f; | |
viewport.y = 0.0f; | |
viewport.width = (float)init.swapchain.extent.width; | |
viewport.height = (float)init.swapchain.extent.height; | |
viewport.minDepth = 0.0f; | |
viewport.maxDepth = 1.0f; | |
VkRect2D scissor = {}; | |
scissor.offset = { 0, 0 }; | |
scissor.extent = init.swapchain.extent; | |
VkPipelineViewportStateCreateInfo viewport_state = {}; | |
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; | |
viewport_state.viewportCount = 1; | |
viewport_state.pViewports = &viewport; | |
viewport_state.scissorCount = 1; | |
viewport_state.pScissors = &scissor; | |
VkPipelineRasterizationStateCreateInfo rasterizer = {}; | |
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; | |
rasterizer.depthClampEnable = VK_FALSE; | |
rasterizer.rasterizerDiscardEnable = VK_FALSE; | |
rasterizer.polygonMode = VK_POLYGON_MODE_FILL; | |
rasterizer.lineWidth = 1.0f; | |
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; | |
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; | |
rasterizer.depthBiasEnable = VK_FALSE; | |
VkPipelineMultisampleStateCreateInfo multisampling = {}; | |
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; | |
multisampling.sampleShadingEnable = VK_FALSE; | |
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.blendEnable = VK_FALSE; | |
VkPipelineColorBlendStateCreateInfo color_blending = {}; | |
color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; | |
color_blending.logicOpEnable = VK_FALSE; | |
color_blending.logicOp = VK_LOGIC_OP_COPY; | |
color_blending.attachmentCount = 1; | |
color_blending.pAttachments = &colorBlendAttachment; | |
color_blending.blendConstants[0] = 0.0f; | |
color_blending.blendConstants[1] = 0.0f; | |
color_blending.blendConstants[2] = 0.0f; | |
color_blending.blendConstants[3] = 0.0f; | |
VkPipelineLayoutCreateInfo pipeline_layout_info = {}; | |
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; | |
pipeline_layout_info.setLayoutCount = 0; | |
pipeline_layout_info.pushConstantRangeCount = 0; | |
if (vkCreatePipelineLayout ( | |
init.device.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 | |
} | |
std::vector<VkDynamicState> dynamic_states = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; | |
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 (); | |
VkGraphicsPipelineCreateInfo pipeline_info = {}; | |
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; | |
pipeline_info.stageCount = 2; | |
pipeline_info.pStages = shader_stages; | |
pipeline_info.pVertexInputState = &vertex_input_info; | |
pipeline_info.pInputAssemblyState = &input_assembly; | |
pipeline_info.pViewportState = &viewport_state; | |
pipeline_info.pRasterizationState = &rasterizer; | |
pipeline_info.pMultisampleState = &multisampling; | |
pipeline_info.pColorBlendState = &color_blending; | |
pipeline_info.pDynamicState = &dynamic_info; | |
pipeline_info.layout = data.pipeline_layout; | |
pipeline_info.renderPass = data.render_pass; | |
pipeline_info.subpass = 0; | |
pipeline_info.basePipelineHandle = VK_NULL_HANDLE; | |
if (vkCreateGraphicsPipelines ( | |
init.device.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 | |
} | |
vkDestroyShaderModule (init.device.device, 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 (); | |
data.framebuffers.resize (data.swapchain_image_views.size ()); | |
for (size_t i = 0; i < data.swapchain_image_views.size (); i++) { | |
VkImageView attachments[] = { data.swapchain_image_views[i] }; | |
VkFramebufferCreateInfo framebuffer_info = {}; | |
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; | |
framebuffer_info.renderPass = data.render_pass; | |
framebuffer_info.attachmentCount = 1; | |
framebuffer_info.pAttachments = attachments; | |
framebuffer_info.width = init.swapchain.extent.width; | |
framebuffer_info.height = init.swapchain.extent.height; | |
framebuffer_info.layers = 1; | |
if (vkCreateFramebuffer (init.device.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) { | |
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 (); | |
if (vkCreateCommandPool (init.device.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 ()); | |
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 (); | |
if (vkAllocateCommandBuffers (init.device.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++) { | |
VkCommandBufferBeginInfo begin_info = {}; | |
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | |
if (vkBeginCommandBuffer (data.command_buffers[i], &begin_info) != VK_SUCCESS) { | |
return -1; // failed to begin recording command buffer | |
} | |
VkRenderPassBeginInfo render_pass_info = {}; | |
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | |
render_pass_info.renderPass = data.render_pass; | |
render_pass_info.framebuffer = data.framebuffers[i]; | |
render_pass_info.renderArea.offset = { 0, 0 }; | |
render_pass_info.renderArea.extent = init.swapchain.extent; | |
VkClearValue clearColor{ { { 0.0f, 0.0f, 0.0f, 1.0f } } }; | |
render_pass_info.clearValueCount = 1; | |
render_pass_info.pClearValues = &clearColor; | |
VkViewport viewport = {}; | |
viewport.x = 0.0f; | |
viewport.y = 0.0f; | |
viewport.width = (float)init.swapchain.extent.width; | |
viewport.height = (float)init.swapchain.extent.height; | |
viewport.minDepth = 0.0f; | |
viewport.maxDepth = 1.0f; | |
VkRect2D scissor = {}; | |
scissor.offset = { 0, 0 }; | |
scissor.extent = init.swapchain.extent; | |
vkCmdSetViewport (data.command_buffers[i], 0, 1, &viewport); | |
vkCmdSetScissor (data.command_buffers[i], 0, 1, &scissor); | |
vkCmdBeginRenderPass (data.command_buffers[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); | |
vkCmdBindPipeline (data.command_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphics_pipeline); | |
vkCmdDraw (data.command_buffers[i], 3, 1, 0, 0); | |
vkCmdEndRenderPass (data.command_buffers[i]); | |
if (vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS) { | |
std::cout << "failed to record command buffer\n"; | |
return -1; // failed to record command buffer! | |
} | |
} | |
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); | |
VkSemaphoreCreateInfo semaphore_info = {}; | |
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
VkFenceCreateInfo fence_info = {}; | |
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; | |
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; | |
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { | |
if (vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS || | |
vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS || | |
vkCreateFence (init.device.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 | |
} | |
} | |
return 0; | |
} | |
int recreate_swapchain (Init& init, RenderData& data) { | |
vkDeviceWaitIdle (init.device.device); | |
vkDestroyCommandPool (init.device.device, data.command_pool, nullptr); | |
for (auto framebuffer : data.framebuffers) { | |
vkDestroyFramebuffer (init.device.device, framebuffer, nullptr); | |
} | |
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; | |
return 0; | |
} | |
int draw_frame (Init& init, RenderData& data) { | |
vkWaitForFences (init.device.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX); | |
uint32_t image_index = 0; | |
VkResult result = vkAcquireNextImageKHR (init.device.device, | |
init.swapchain.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); | |
} 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) { | |
vkWaitForFences (init.device.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]; | |
VkSubmitInfo submitInfo = {}; | |
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | |
VkSemaphore wait_semaphores[] = { data.available_semaphores[data.current_frame] }; | |
VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; | |
submitInfo.waitSemaphoreCount = 1; | |
submitInfo.pWaitSemaphores = wait_semaphores; | |
submitInfo.pWaitDstStageMask = wait_stages; | |
submitInfo.commandBufferCount = 1; | |
submitInfo.pCommandBuffers = &data.command_buffers[image_index]; | |
VkSemaphore signal_semaphores[] = { data.finished_semaphore[data.current_frame] }; | |
submitInfo.signalSemaphoreCount = 1; | |
submitInfo.pSignalSemaphores = signal_semaphores; | |
vkResetFences (init.device.device, 1, &data.in_flight_fences[data.current_frame]); | |
if (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 | |
} | |
VkPresentInfoKHR present_info = {}; | |
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; | |
present_info.waitSemaphoreCount = 1; | |
present_info.pWaitSemaphores = signal_semaphores; | |
VkSwapchainKHR swapChains[] = { init.swapchain.swapchain }; | |
present_info.swapchainCount = 1; | |
present_info.pSwapchains = swapChains; | |
present_info.pImageIndices = &image_index; | |
result = vkQueuePresentKHR (data.present_queue, &present_info); | |
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { | |
return recreate_swapchain (init, data); | |
} else if (result != VK_SUCCESS) { | |
std::cout << "failed to present swapchain image\n"; | |
return -1; | |
} | |
data.current_frame = (data.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; | |
return 0; | |
} | |
void cleanup (Init& init, RenderData& data) { | |
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { | |
vkDestroySemaphore (init.device.device, data.finished_semaphore[i], nullptr); | |
vkDestroySemaphore (init.device.device, data.available_semaphores[i], nullptr); | |
vkDestroyFence (init.device.device, data.in_flight_fences[i], nullptr); | |
} | |
vkDestroyCommandPool (init.device.device, data.command_pool, nullptr); | |
for (auto framebuffer : data.framebuffers) { | |
vkDestroyFramebuffer (init.device.device, framebuffer, nullptr); | |
} | |
vkDestroyPipeline (init.device.device, data.graphics_pipeline, nullptr); | |
vkDestroyPipelineLayout (init.device.device, data.pipeline_layout, nullptr); | |
vkDestroyRenderPass (init.device.device, data.render_pass, nullptr); | |
init.swapchain.destroy_image_views (data.swapchain_image_views); | |
vkb::destroy_swapchain (init.swapchain); | |
vkb::destroy_device (init.device); | |
vkDestroySurfaceKHR (init.instance.instance, init.surface, nullptr); | |
vkb::destroy_instance (init.instance); | |
destroy_window_glfw (init.window); | |
} | |
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; | |
while (!glfwWindowShouldClose (init.window)) { | |
glfwPollEvents (); | |
int res = draw_frame (init, render_data); | |
if (res != 0) { | |
std::cout << "failed to draw frame \n"; | |
return -1; | |
} | |
} | |
vkDeviceWaitIdle (init.device.device); | |
cleanup (init, render_data); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment