diff --git a/CMakeLists.txt b/CMakeLists.txt index 48ba590..7a224e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,13 +25,13 @@ target_link_libraries(vk-bootstrap-test vk-bootstrap) target_link_libraries(vk-bootstrap-test glfw) target_link_libraries(vk-bootstrap-test Catch2) -add_executable(vk-bootstrap-triangle tests/triangle.cpp) +add_executable(vk-bootstrap-triangle example/triangle.cpp) target_link_libraries(vk-bootstrap-triangle vk-bootstrap) target_link_libraries(vk-bootstrap-triangle glfw) add_custom_command( - TARGET vk-bootstrap-triangle POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tests/shaders ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR} + TARGET vk-bootstrap-triangle POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/example/shaders ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR} ) endif() \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 5d1e4c5..02bb6d6 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright © 2020 +Copyright © 2020 Charles Giessen (charles-lunarg@gmail.com) 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: diff --git a/README.md b/README.md index 30d9e10..55127e5 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,13 @@ This library simplifies the tedious process of: * Getting Queues * Swapchain Creation +It also adds several convenience for: + +* enabling validation layers +* setting up a debug callback +* automate getting a drawable surface +* selecting a gpu based on a small set of common criteria + ## Example ```cpp @@ -17,29 +24,33 @@ vkb::InstanceBuilder builder; builder.setup_validation_layers() .set_app_name ("example") .set_default_debug_messenger (); -auto inst_ret = builder.build (); -vkb::Instance inst; -if (inst_ret.has_value()) { - // successfully created instance - inst = inst_ret.value(); +auto inst_ret = builder.build(); +if (!inst_ret.has_value()) { + // error } +vkb::Instance inst = inst_ret.value(); -vkb::PhysicalDeviceSelector(inst); +vkb::PhysicalDeviceSelector selector{ inst }; selector.set_surface (/* from user created window*/) - .set_minimum_version (1, 0) - .require_dedicated_transfer_queue(); + .set_minimum_version (1, 0) + .require_dedicated_transfer_queue(); auto phys_ret = selector.select (); -vkb::PhysicalDevice phys; -if (phys_ret.has_value()) { - // successfully selected a sufficient physical device - phys = phys_ret.value(); +if (!phys_ret.has_value()) { + // error } +vkb::PhysicalDevice physical_device = phys_ret.value(); -vkb::DeviceBuilder device_builder(phys_dev); +vkb::DeviceBuilder device_builder{ physical_device }; auto dev_ret = device_builder.build (); -if(dev_ret.has_value()){ - // successfully created a vulkan device +if (!dev_ret.has_value()){ + // error } +vkb::Device device = dev_ret.value(); + +VkQueue graphics_queue = get_queue_graphics(device).value(); +VkQueue compute_queue = get_queue_compute(device).value(); +VkQueue transfer_queue = get_queue_transfer(device).value(); + ``` ## Building @@ -70,4 +81,10 @@ Then return to the build directory and enable tests with `VK_BOOTSTRAP_TEST` cmake ../path/to/vk-bootstrap/ -DVK_BOOTSTRAP_TEST=ON ``` +## Todo's +* Package library to be usable +* More examples +* Testing +* Documenting API +* Fleshing out device configuration diff --git a/tests/shaders/frag.glsl b/example/shaders/frag.glsl similarity index 100% rename from tests/shaders/frag.glsl rename to example/shaders/frag.glsl diff --git a/tests/shaders/frag.spv b/example/shaders/frag.spv similarity index 100% rename from tests/shaders/frag.spv rename to example/shaders/frag.spv diff --git a/tests/shaders/vert.glsl b/example/shaders/vert.glsl similarity index 100% rename from tests/shaders/vert.glsl rename to example/shaders/vert.glsl diff --git a/tests/shaders/vert.spv b/example/shaders/vert.spv similarity index 100% rename from tests/shaders/vert.spv rename to example/shaders/vert.spv diff --git a/example/triangle.cpp b/example/triangle.cpp new file mode 100644 index 0000000..e6c9e7f --- /dev/null +++ b/example/triangle.cpp @@ -0,0 +1,541 @@ +#include + +#include +#include +#include + +#include "../tests/common.h" + +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 swapchain_images; + std::vector swapchain_image_views; + std::vector framebuffers; + + VkRenderPass render_pass; + VkPipelineLayout pipeline_layout; + VkPipeline graphics_pipeline; + + VkCommandPool command_pool; + std::vector command_buffers; + + std::vector available_semaphores; + std::vector finished_semaphore; + std::vector in_flight_fences; + std::vector image_in_flight; + size_t current_frame = 0; +}; + +int device_initialization (Init& init) +{ + init.window = create_window_glfw (false); + + vkb::InstanceBuilder instance_builder; + auto instance_ret = instance_builder.set_default_debug_messenger ().setup_validation_layers ().build (); + if (!instance_ret) + { + std::cout << instance_ret.error ().msg << "\n"; + } + 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 ().msg << "\n"; + } + 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 ().msg << "\n"; + } + init.device = device_ret.value (); + + vkb::SwapchainBuilder swapchain_builder{ init.device }; + auto swap_ret = + swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build (); + if (!swap_ret) + { + std::cout << swap_ret.error ().msg << "\n"; + } + init.swapchain = swap_ret.value (); + return 0; +} + +int get_queues (Init& init, RenderData& data) +{ + data.graphics_queue = vkb::get_queue_graphics (init.device).value (); + data.present_queue = vkb::get_queue_graphics (init.device).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) + { + return -1; // failed to create render pass! + } + return 0; +} + +std::vector 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 buffer (file_size); + + file.seekg (0); + file.read (buffer.data (), file_size); + + file.close (); + + return buffer; +} + +VkShaderModule createShaderModule (Init& init, const std::vector& code) +{ + VkShaderModuleCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + create_info.codeSize = code.size (); + create_info.pCode = reinterpret_cast (code.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) +{ + auto vert_code = readFile ("vert.spv"); + auto frag_code = readFile ("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) + { + 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 = vert_module; + vert_stage_info.pName = "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 = frag_module; + frag_stage_info.pName = "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) + { + return -1; // failed to create pipeline layout + } + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shader_stages; + pipelineInfo.pVertexInputState = &vertex_input_info; + pipelineInfo.pInputAssemblyState = &input_assembly; + pipelineInfo.pViewportState = &viewport_state; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pColorBlendState = &color_blending; + pipelineInfo.layout = data.pipeline_layout; + pipelineInfo.renderPass = data.render_pass; + pipelineInfo.subpass = 0; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + + if (vkCreateGraphicsPipelines ( + init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphics_pipeline) != VK_SUCCESS) + { + return -1; // failed to create graphics pipeline + } + + vkDestroyShaderModule (init.device.device, frag_module, nullptr); + vkDestroyShaderModule (init.device.device, vert_module, nullptr); + return 0; +} + +int create_framebuffers (Init& init, RenderData& data) +{ + data.swapchain_images = vkb::get_swapchain_images (init.swapchain).value (); + // init.swapchain.image_count = data.swapchain_images.size (); + data.swapchain_image_views = + vkb::get_swapchain_image_views (init.swapchain, data.swapchain_images).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 = vkb::get_queue_index_graphics (init.device); + + if (vkCreateCommandPool (init.device.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) + { + 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; + + 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) + { + 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) + { + return -1; // failed to create synchronization objects for a frame + } + } + 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; + vkAcquireNextImageKHR (init.device.device, + init.swapchain.swapchain, + UINT64_MAX, + data.available_semaphores[data.current_frame], + VK_NULL_HANDLE, + &image_index); + + 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) + { + 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; + + vkQueuePresentKHR (data.present_queue, &present_info); + + 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); + + for (auto imageView : data.swapchain_image_views) + { + vkDestroyImageView (init.device.device, imageView, nullptr); + } + + 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; + + int res = 0; + res = device_initialization (init); + res = get_queues (init, render_data); + res = create_render_pass (init, render_data); + res = create_graphics_pipeline (init, render_data); + res = create_framebuffers (init, render_data); + res = create_command_pool (init, render_data); + res = create_command_buffers (init, render_data); + res = create_sync_objects (init, render_data); + + if (res != 0) + { + std::cout << "failed to initialize vulkan\n"; + 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; +} \ No newline at end of file diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index 17cc198..7273ebd 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -6,7 +6,7 @@ namespace vkb { -const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s) +const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s) { switch (s) { @@ -22,7 +22,7 @@ const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s) return "UNKNOWN"; } } -const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s) +const char* to_string_message_type (VkDebugUtilsMessageTypeFlagsEXT s) { switch (s) { @@ -84,8 +84,8 @@ VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageS const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { - auto ms = DebugMessageSeverity (messageSeverity); - auto mt = DebugMessageType (messageType); + auto ms = to_string_message_severity (messageSeverity); + auto mt = to_string_message_type (messageType); printf ("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage); return VK_FALSE; } @@ -130,10 +130,13 @@ void setup_pNext_chain (T& structure, std::vector& structs) void destroy_instance (Instance instance) { - if (instance.debug_messenger != nullptr) - detail::destroy_debug_utils_messenger (instance.instance, instance.debug_messenger, instance.allocator); if (instance.instance != VK_NULL_HANDLE) + { + if (instance.debug_messenger != nullptr) + detail::destroy_debug_utils_messenger ( + instance.instance, instance.debug_messenger, instance.allocator); vkDestroyInstance (instance.instance, instance.allocator); + } } detail::Expected InstanceBuilder::build () @@ -485,31 +488,31 @@ detail::QueueFamilies find_queue_families (VkPhysicalDevice phys_device, VkSurfa bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested) { // clang-format off - if (requested.robustBufferAccess && ! supported.robustBufferAccess) return false; - if (requested.fullDrawIndexUint32 && ! supported.fullDrawIndexUint32) return false; - if (requested.imageCubeArray && ! supported.imageCubeArray) return false; - if (requested.independentBlend && ! supported.independentBlend) return false; - if (requested.geometryShader && ! supported.geometryShader) return false; - if (requested.tessellationShader && ! supported.tessellationShader) return false; - if (requested.sampleRateShading && ! supported.sampleRateShading) return false; - if (requested.dualSrcBlend && ! supported.dualSrcBlend) return false; - if (requested.logicOp && ! supported.logicOp) return false; - if (requested.multiDrawIndirect && ! supported.multiDrawIndirect) return false; - if (requested.drawIndirectFirstInstance && ! supported.drawIndirectFirstInstance) return false; - if (requested.depthClamp && ! supported.depthClamp) return false; - if (requested.depthBiasClamp && ! supported.depthBiasClamp) return false; - if (requested.fillModeNonSolid && ! supported.fillModeNonSolid) return false; - if (requested.depthBounds && ! supported.depthBounds) return false; - if (requested.wideLines && ! supported.wideLines) return false; - if (requested.largePoints && ! supported.largePoints) return false; - if (requested.alphaToOne && ! supported.alphaToOne) return false; - if (requested.multiViewport && ! supported.multiViewport) return false; - if (requested.samplerAnisotropy && ! supported.samplerAnisotropy) return false; - if (requested.textureCompressionETC2 && ! supported.textureCompressionETC2) return false; - if (requested.textureCompressionASTC_LDR && ! supported.textureCompressionASTC_LDR) return false; - if (requested.textureCompressionBC && ! supported.textureCompressionBC) return false; - if (requested.occlusionQueryPrecise && ! supported.occlusionQueryPrecise) return false; - if (requested.pipelineStatisticsQuery && ! supported.pipelineStatisticsQuery) return false; + if (requested.robustBufferAccess && !supported.robustBufferAccess) return false; + if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false; + if (requested.imageCubeArray && !supported.imageCubeArray) return false; + if (requested.independentBlend && !supported.independentBlend) return false; + if (requested.geometryShader && !supported.geometryShader) return false; + if (requested.tessellationShader && !supported.tessellationShader) return false; + if (requested.sampleRateShading && !supported.sampleRateShading) return false; + if (requested.dualSrcBlend && !supported.dualSrcBlend) return false; + if (requested.logicOp && !supported.logicOp) return false; + if (requested.multiDrawIndirect && !supported.multiDrawIndirect) return false; + if (requested.drawIndirectFirstInstance && !supported.drawIndirectFirstInstance) return false; + if (requested.depthClamp && !supported.depthClamp) return false; + if (requested.depthBiasClamp && !supported.depthBiasClamp) return false; + if (requested.fillModeNonSolid && !supported.fillModeNonSolid) return false; + if (requested.depthBounds && !supported.depthBounds) return false; + if (requested.wideLines && !supported.wideLines) return false; + if (requested.largePoints && !supported.largePoints) return false; + if (requested.alphaToOne && !supported.alphaToOne) return false; + if (requested.multiViewport && !supported.multiViewport) return false; + if (requested.samplerAnisotropy && !supported.samplerAnisotropy) return false; + if (requested.textureCompressionETC2 && !supported.textureCompressionETC2) return false; + if (requested.textureCompressionASTC_LDR && !supported.textureCompressionASTC_LDR) return false; + if (requested.textureCompressionBC && !supported.textureCompressionBC) return false; + if (requested.occlusionQueryPrecise && !supported.occlusionQueryPrecise) return false; + if (requested.pipelineStatisticsQuery && !supported.pipelineStatisticsQuery) return false; if (requested.vertexPipelineStoresAndAtomics && !supported.vertexPipelineStoresAndAtomics) return false; if (requested.fragmentStoresAndAtomics && !supported.fragmentStoresAndAtomics) return false; if (requested.shaderTessellationAndGeometryPointSize && !supported.shaderTessellationAndGeometryPointSize) return false; @@ -961,6 +964,9 @@ SwapchainBuilder::SwapchainBuilder (Device const& device) detail::Expected SwapchainBuilder::build () { + if (info.desired_formats.size () == 0) use_default_format_selection (); + if (info.desired_present_modes.size () == 0) use_default_present_mode_selection (); + auto surface_support = detail::query_surface_support_details (info.physical_device.phys_device, info.surface); if (!surface_support.has_value ()) return surface_support.error (); @@ -1016,16 +1022,12 @@ detail::Expected SwapchainBuilder::build () { return detail::Error{ res, "Failed to create swapchain" }; } - auto swapchain_images = - detail::get_vector (vkGetSwapchainImagesKHR, info.device, swapchain.swapchain); - if (!swapchain_images) - { - return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to get swapchain Images" }; - } - swapchain.images = swapchain_images.value (); + swapchain.device = info.device; swapchain.image_format = surface_format.format; swapchain.extent = extent; + auto images = get_swapchain_images (swapchain); + swapchain.image_count = images.value ().size (); return swapchain; } detail::Expected SwapchainBuilder::recreate (Swapchain const& swapchain) @@ -1033,11 +1035,52 @@ detail::Expected SwapchainBuilder::recreate (Swapchain cons info.old_swapchain = swapchain.swapchain; return build (); } +detail::Expected, VkResult> get_swapchain_images (Swapchain const& swapchain) +{ + auto swapchain_images = + detail::get_vector (vkGetSwapchainImagesKHR, swapchain.device, swapchain.swapchain); + if (!swapchain_images) + { + return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to get swapchain Images" }; + } + return swapchain_images.value (); +} + +detail::Expected, VkResult> get_swapchain_image_views ( + Swapchain const& swapchain, std::vector const& images) +{ + std::vector views; + views.resize (swapchain.image_count); + + for (size_t i = 0; i < swapchain.image_count; i++) + { + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = images[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = swapchain.image_format; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + + if (vkCreateImageView (swapchain.device, &createInfo, nullptr, &views[i]) != VK_SUCCESS) + { + return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to create image views" }; + } + } + return views; +} + void destroy_swapchain (Swapchain const& swapchain) { - if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE && - swapchain.allocator != VK_NULL_HANDLE) + if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE) vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocator); } @@ -1072,8 +1115,6 @@ SwapchainBuilder& SwapchainBuilder::use_default_present_mode_selection () { info.desired_present_modes.push_back (VK_PRESENT_MODE_MAILBOX_KHR); info.desired_present_modes.push_back (VK_PRESENT_MODE_FIFO_KHR); - info.desired_present_modes.push_back (VK_PRESENT_MODE_FIFO_RELAXED_KHR); - info.desired_present_modes.push_back (VK_PRESENT_MODE_IMMEDIATE_KHR); return *this; } diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 8b2ef79..2833ff9 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -178,9 +178,8 @@ bool check_layers_supported (std::vector layer_names); } // namespace detail -const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s); -const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s); - +const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s); +const char* to_string_message_type (VkDebugUtilsMessageTypeFlagsEXT s); struct Instance { @@ -455,12 +454,15 @@ struct Swapchain VkDevice device = VK_NULL_HANDLE; VkSwapchainKHR swapchain = VK_NULL_HANDLE; VkAllocationCallbacks* allocator = VK_NULL_HANDLE; - std::vector images; + uint32_t image_count = 0; VkFormat image_format = VK_FORMAT_UNDEFINED; VkExtent2D extent = { 0, 0 }; }; void destroy_swapchain (Swapchain const& swapchain); +detail::Expected, VkResult> get_swapchain_images (Swapchain const& swapchain); +detail::Expected, VkResult> get_swapchain_image_views ( + Swapchain const& swapchain, std::vector const& images); class SwapchainBuilder { @@ -481,8 +483,6 @@ class SwapchainBuilder SwapchainBuilder& add_fallback_present_mode (VkPresentModeKHR present_mode); SwapchainBuilder& use_default_present_mode_selection (); - - private: struct SwapchainInfo { diff --git a/tests/common.h b/tests/common.h index 1986b18..6782e96 100644 --- a/tests/common.h +++ b/tests/common.h @@ -10,10 +10,12 @@ #include "../src/VkBootstrap.h" -GLFWwindow* create_window_glfw () +GLFWwindow* create_window_glfw (bool resize = true) { glfwInit (); glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API); + if (!resize) glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE); + return glfwCreateWindow (640, 480, "Vulkan Triangle", NULL, NULL); } void destroy_window_glfw (GLFWwindow* window) diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index c38690e..529fe2a 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -49,8 +49,8 @@ int test_instance_basic () VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) -> VkBool32 { - auto ms = vkb::DebugMessageSeverity (messageSeverity); - auto mt = vkb::DebugMessageType (messageType); + auto ms = vkb::to_string_message_severity (messageSeverity); + auto mt = vkb::to_string_message_type (messageType); printf ("[%s: %s](user defined)\n%s\n", ms, mt, pCallbackData->pMessage); return VK_FALSE; }) diff --git a/tests/triangle.cpp b/tests/triangle.cpp deleted file mode 100644 index f220a91..0000000 --- a/tests/triangle.cpp +++ /dev/null @@ -1,542 +0,0 @@ -#include - -#include -#include -#include - -#include "common.h" - -struct Init -{ - GLFWwindow* window; - vkb::Instance instance; - VkSurfaceKHR surface; - vkb::Device device; - vkb::Swapchain swapchain; -}; - -struct RenderData -{ - VkQueue graphicsQueue; - VkQueue presentQueue; - - std::vector swapChainImageViews; - std::vector swapChainFramebuffers; - - VkRenderPass renderPass; - VkPipelineLayout pipelineLayout; - VkPipeline graphicsPipeline; - - VkCommandPool commandPool; - std::vector commandBuffers; - - std::vector imageAvailableSemaphores; - std::vector renderFinishedSemaphores; - std::vector inFlightFences; - std::vector imagesInFlight; - size_t currentFrame = 0; -}; - -void device_initialization (Init& init) -{ - init.window = create_window_glfw (); - - vkb::InstanceBuilder instance_builder; - auto instance_ret = instance_builder.set_default_debug_messenger ().setup_validation_layers ().build (); - if (!instance_ret) - { - std::cout << instance_ret.error ().msg << "\n"; - } - 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 ().msg << "\n"; - } - 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 ().msg << "\n"; - } - init.device = device_ret.value (); - - vkb::SwapchainBuilder swapchain_builder (init.device); - auto swap_ret = - swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build (); - if (!swap_ret) - { - std::cout << swap_ret.error ().msg << "\n"; - } - init.swapchain = swap_ret.value (); -} - -void get_queues (Init& init, RenderData& data) -{ - data.graphicsQueue = vkb::get_queue_graphics (init.device).value (); - data.presentQueue = vkb::get_queue_graphics (init.device).value (); -} - -void createImageViews (Init& init, RenderData& data) -{ - data.swapChainImageViews.resize (init.swapchain.images.size ()); - - for (size_t i = 0; i < init.swapchain.images.size (); i++) - { - VkImageViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = init.swapchain.images[i]; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = init.swapchain.image_format; - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - - if (vkCreateImageView (init.device.device, &createInfo, nullptr, &data.swapChainImageViews[i]) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create image views!"); - } - } -} - -void createRenderPass (Init& init, RenderData& data) -{ - VkAttachmentDescription colorAttachment = {}; - colorAttachment.format = init.swapchain.image_format; - colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference colorAttachmentRef = {}; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - - 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 renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = 1; - renderPassInfo.pAttachments = &colorAttachment; - renderPassInfo.subpassCount = 1; - renderPassInfo.pSubpasses = &subpass; - renderPassInfo.dependencyCount = 1; - renderPassInfo.pDependencies = &dependency; - - if (vkCreateRenderPass (init.device.device, &renderPassInfo, nullptr, &data.renderPass) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create render pass!"); - } -} - -std::vector 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 fileSize = (size_t)file.tellg (); - std::vector buffer (fileSize); - - file.seekg (0); - file.read (buffer.data (), fileSize); - - file.close (); - - return buffer; -} - -VkShaderModule createShaderModule (Init& init, const std::vector& code) -{ - VkShaderModuleCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = code.size (); - createInfo.pCode = reinterpret_cast (code.data ()); - - VkShaderModule shaderModule; - if (vkCreateShaderModule (init.device.device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create shader module!"); - } - - return shaderModule; -} - -void createGraphicsPipeline (Init& init, RenderData& data) -{ - auto vertShaderCode = readFile ("vert.spv"); - auto fragShaderCode = readFile ("frag.spv"); - - VkShaderModule vertShaderModule = createShaderModule (init, vertShaderCode); - VkShaderModule fragShaderModule = createShaderModule (init, fragShaderCode); - - VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; - vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertShaderStageInfo.module = vertShaderModule; - vertShaderStageInfo.pName = "main"; - - VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; - fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - fragShaderStageInfo.module = fragShaderModule; - fragShaderStageInfo.pName = "main"; - - VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo }; - - VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; - vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputInfo.vertexBindingDescriptionCount = 0; - vertexInputInfo.vertexAttributeDescriptionCount = 0; - - VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssembly.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 viewportState = {}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; - viewportState.scissorCount = 1; - viewportState.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 colorBlending = {}; - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.logicOpEnable = VK_FALSE; - colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - colorBlending.blendConstants[0] = 0.0f; - colorBlending.blendConstants[1] = 0.0f; - colorBlending.blendConstants[2] = 0.0f; - colorBlending.blendConstants[3] = 0.0f; - - VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 0; - pipelineLayoutInfo.pushConstantRangeCount = 0; - - if (vkCreatePipelineLayout (init.device.device, &pipelineLayoutInfo, nullptr, &data.pipelineLayout) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create pipeline layout!"); - } - - VkGraphicsPipelineCreateInfo pipelineInfo = {}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = 2; - pipelineInfo.pStages = shaderStages; - pipelineInfo.pVertexInputState = &vertexInputInfo; - pipelineInfo.pInputAssemblyState = &inputAssembly; - pipelineInfo.pViewportState = &viewportState; - pipelineInfo.pRasterizationState = &rasterizer; - pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pColorBlendState = &colorBlending; - pipelineInfo.layout = data.pipelineLayout; - pipelineInfo.renderPass = data.renderPass; - pipelineInfo.subpass = 0; - pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - - if (vkCreateGraphicsPipelines ( - init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphicsPipeline) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create graphics pipeline!"); - } - - vkDestroyShaderModule (init.device.device, fragShaderModule, nullptr); - vkDestroyShaderModule (init.device.device, vertShaderModule, nullptr); -} - -void createFramebuffers (Init& init, RenderData& data) -{ - data.swapChainFramebuffers.resize (data.swapChainImageViews.size ()); - - for (size_t i = 0; i < data.swapChainImageViews.size (); i++) - { - VkImageView attachments[] = { data.swapChainImageViews[i] }; - - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = data.renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = attachments; - framebufferInfo.width = init.swapchain.extent.width; - framebufferInfo.height = init.swapchain.extent.height; - framebufferInfo.layers = 1; - - if (vkCreateFramebuffer ( - init.device.device, &framebufferInfo, nullptr, &data.swapChainFramebuffers[i]) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create framebuffer!"); - } - } -} - -void createCommandPool (Init& init, RenderData& data) -{ - - VkCommandPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.queueFamilyIndex = vkb::get_queue_index_graphics (init.device); - - if (vkCreateCommandPool (init.device.device, &poolInfo, nullptr, &data.commandPool) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create command pool!"); - } -} - -void createCommandBuffers (Init& init, RenderData& data) -{ - data.commandBuffers.resize (data.swapChainFramebuffers.size ()); - - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = data.commandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (uint32_t)data.commandBuffers.size (); - - if (vkAllocateCommandBuffers (init.device.device, &allocInfo, data.commandBuffers.data ()) != VK_SUCCESS) - { - throw std::runtime_error ("failed to allocate command buffers!"); - } - - for (size_t i = 0; i < data.commandBuffers.size (); i++) - { - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - if (vkBeginCommandBuffer (data.commandBuffers[i], &beginInfo) != VK_SUCCESS) - { - throw std::runtime_error ("failed to begin recording command buffer!"); - } - - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = data.renderPass; - renderPassInfo.framebuffer = data.swapChainFramebuffers[i]; - renderPassInfo.renderArea.offset = { 0, 0 }; - renderPassInfo.renderArea.extent = init.swapchain.extent; - - VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f }; - renderPassInfo.clearValueCount = 1; - renderPassInfo.pClearValues = &clearColor; - - vkCmdBeginRenderPass (data.commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdBindPipeline (data.commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphicsPipeline); - - vkCmdDraw (data.commandBuffers[i], 3, 1, 0, 0); - - vkCmdEndRenderPass (data.commandBuffers[i]); - - if (vkEndCommandBuffer (data.commandBuffers[i]) != VK_SUCCESS) - { - throw std::runtime_error ("failed to record command buffer!"); - } - } -} - -void createSyncObjects (Init& init, RenderData& data) -{ - data.imageAvailableSemaphores.resize (init.swapchain.images.size ()); - data.renderFinishedSemaphores.resize (init.swapchain.images.size ()); - data.inFlightFences.resize (init.swapchain.images.size ()); - data.imagesInFlight.resize (init.swapchain.images.size (), VK_NULL_HANDLE); - - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - for (size_t i = 0; i < init.swapchain.images.size (); i++) - { - if (vkCreateSemaphore ( - init.device.device, &semaphoreInfo, nullptr, &data.imageAvailableSemaphores[i]) != VK_SUCCESS || - vkCreateSemaphore ( - init.device.device, &semaphoreInfo, nullptr, &data.renderFinishedSemaphores[i]) != VK_SUCCESS || - vkCreateFence (init.device.device, &fenceInfo, nullptr, &data.inFlightFences[i]) != VK_SUCCESS) - { - throw std::runtime_error ("failed to create synchronization objects for a frame!"); - } - } -} - -void drawFrame (Init& init, RenderData& data) -{ - vkWaitForFences (init.device.device, 1, &data.inFlightFences[data.currentFrame], VK_TRUE, UINT64_MAX); - - uint32_t imageIndex; - vkAcquireNextImageKHR (init.device.device, - init.swapchain.swapchain, - UINT64_MAX, - data.imageAvailableSemaphores[data.currentFrame], - VK_NULL_HANDLE, - &imageIndex); - - if (data.imagesInFlight[imageIndex] != VK_NULL_HANDLE) - { - vkWaitForFences (init.device.device, 1, &data.imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); - } - data.imagesInFlight[imageIndex] = data.inFlightFences[data.currentFrame]; - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - - VkSemaphore waitSemaphores[] = { data.imageAvailableSemaphores[data.currentFrame] }; - VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = waitSemaphores; - submitInfo.pWaitDstStageMask = waitStages; - - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &data.commandBuffers[imageIndex]; - - VkSemaphore signalSemaphores[] = { data.renderFinishedSemaphores[data.currentFrame] }; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = signalSemaphores; - - vkResetFences (init.device.device, 1, &data.inFlightFences[data.currentFrame]); - - if (vkQueueSubmit (data.graphicsQueue, 1, &submitInfo, data.inFlightFences[data.currentFrame]) != VK_SUCCESS) - { - throw std::runtime_error ("failed to submit draw command buffer!"); - } - - VkPresentInfoKHR presentInfo = {}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = signalSemaphores; - - VkSwapchainKHR swapChains[] = { init.swapchain.swapchain }; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = swapChains; - - presentInfo.pImageIndices = &imageIndex; - - vkQueuePresentKHR (data.presentQueue, &presentInfo); - - data.currentFrame = (data.currentFrame + 1) % init.swapchain.images.size (); -} - -void cleanup (Init& init, RenderData& data) -{ - for (size_t i = 0; i < init.swapchain.images.size (); i++) - { - vkDestroySemaphore (init.device.device, data.renderFinishedSemaphores[i], nullptr); - vkDestroySemaphore (init.device.device, data.imageAvailableSemaphores[i], nullptr); - vkDestroyFence (init.device.device, data.inFlightFences[i], nullptr); - } - - vkDestroyCommandPool (init.device.device, data.commandPool, nullptr); - - for (auto framebuffer : data.swapChainFramebuffers) - { - vkDestroyFramebuffer (init.device.device, framebuffer, nullptr); - } - - vkDestroyPipeline (init.device.device, data.graphicsPipeline, nullptr); - vkDestroyPipelineLayout (init.device.device, data.pipelineLayout, nullptr); - vkDestroyRenderPass (init.device.device, data.renderPass, nullptr); - - for (auto imageView : data.swapChainImageViews) - { - vkDestroyImageView (init.device.device, imageView, nullptr); - } - - 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; - - - device_initialization (init); - get_queues (init, render_data); - createImageViews (init, render_data); - createRenderPass (init, render_data); - createGraphicsPipeline (init, render_data); - createFramebuffers (init, render_data); - createCommandPool (init, render_data); - createCommandBuffers (init, render_data); - createSyncObjects (init, render_data); - - while (!glfwWindowShouldClose (init.window)) - { - glfwPollEvents (); - drawFrame (init, render_data); - } - vkDeviceWaitIdle (init.device.device); - - cleanup (init, render_data); - return 0; -} \ No newline at end of file