summaryrefslogtreecommitdiff
path: root/src/vulkan_swapchain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vulkan_swapchain.cpp')
-rw-r--r--src/vulkan_swapchain.cpp253
1 files changed, 244 insertions, 9 deletions
diff --git a/src/vulkan_swapchain.cpp b/src/vulkan_swapchain.cpp
index fde4388..41d27a5 100644
--- a/src/vulkan_swapchain.cpp
+++ b/src/vulkan_swapchain.cpp
@@ -1,6 +1,7 @@
#include "vulkan_swapchain.h"
#include "GLFW/glfw3.h"
+#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_vulkan.h"
#include "vulkan/vulkan_core.h"
@@ -42,13 +43,18 @@ void Swapchain::resize(uint32_t new_width, uint32_t new_height) {
vkDestroySwapchainKHR(device.device, swapchain, nullptr);
}
+ VkSurfaceCapabilitiesKHR surface_capabilities;
+ CHECK_VULKAN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+ device.physical_device,
+ surface,
+ &surface_capabilities));
VkSwapchainCreateInfoKHR swapchain_create_info = {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.surface = surface,
.minImageCount = SWAPCHAIN_IMAGE_COUNT,
.imageFormat = VK_FORMAT_B8G8R8A8_UNORM,
.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
- .imageExtent = {width, height},
+ .imageExtent = {new_width, new_height},
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
@@ -63,7 +69,6 @@ void Swapchain::resize(uint32_t new_width, uint32_t new_height) {
&swapchain_create_info,
nullptr,
&swapchain));
-
// images
uint32_t image_count = 0;
CHECK_VULKAN(vkGetSwapchainImagesKHR(
@@ -133,12 +138,21 @@ void Swapchain::resize(uint32_t new_width, uint32_t new_height) {
{width, height},
VK_FORMAT_B8G8R8A8_UNORM,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
- VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE);
+ VmaAllocationCreateInfo {
+ .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
+ .usage = VMA_MEMORY_USAGE_AUTO,
+ });
}
-Swapchain::Swapchain(
- GLFWwindow *window,
- iris::Device device) : device(device), window(window)
+Swapchain::Swapchain(GLFWwindow *window,
+ iris::Device device,
+ uint32_t width,
+ uint32_t height)
+ : device(device)
+ , window(window)
+ , width(width)
+ , height(height)
+ , cmd_buf(device.create_command_buffer())
{
if (!glfwVulkanSupported()) {
std::cerr << "GLFW failed to find Vulkan support" << std::endl;
@@ -146,6 +160,7 @@ Swapchain::Swapchain(
abort();
}
+ std::cerr << "Creating surface" << std::endl;
// Create the surface
CHECK_VULKAN(glfwCreateWindowSurface(
device.instance,
@@ -242,6 +257,23 @@ Swapchain::Swapchain(
// Create swapchain and image/imageview/framebuffers
this->resize(width, height);
+ // Create semaphores
+ for (uint32_t i = 0; i < SWAPCHAIN_IMAGE_COUNT; i++) {
+ VkSemaphoreCreateInfo semaphore_info = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ };
+ CHECK_VULKAN(vkCreateSemaphore(
+ device.device,
+ &semaphore_info,
+ nullptr,
+ &image_available_semaphores[i]));
+ CHECK_VULKAN(vkCreateSemaphore(
+ device.device,
+ &semaphore_info,
+ nullptr,
+ &render_finished_semaphores[i]));
+ }
+
// Create descriptor pool
VkDescriptorPoolSize pool_size = {
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
@@ -260,6 +292,15 @@ Swapchain::Swapchain(
&descriptor_pool));
// initialize ImGui
+ imgui_context = ImGui::CreateContext();
+ ImGui::SetCurrentContext(imgui_context);
+
+ ImGuiIO &io = ImGui::GetIO();
+ io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
+ io.FontDefault = io.Fonts->AddFontFromFileTTF(
+ "assets/Roboto-Regular.ttf",
+ 16.0f);
+
ImGui_ImplGlfw_InitForVulkan(window, true);
ImGui_ImplVulkan_InitInfo init_info = {
.Instance = device.instance,
@@ -268,28 +309,222 @@ Swapchain::Swapchain(
.QueueFamily = device.main_queue_family_index,
.Queue = device.graphics_queue,
.DescriptorPool = descriptor_pool,
+ .RenderPass = render_pass,
.MinImageCount = SWAPCHAIN_IMAGE_COUNT,
.ImageCount = SWAPCHAIN_IMAGE_COUNT,
.MSAASamples = VK_SAMPLE_COUNT_1_BIT,
-
- // optional
- .CheckVkResultFn = [](const VkResult err) { CHECK_VULKAN(err); },
};
ImGui_ImplVulkan_Init(&init_info);
}
+void Swapchain::start_frame() {
+ VkCommandBufferBeginInfo begin_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ };
+ CHECK_VULKAN(vkBeginCommandBuffer(cmd_buf.buffer, &begin_info));
+}
+
+void Swapchain::display(Texture2D& texture) {
+ std::cerr << "Displaying" << std::endl;
+ VkResult present_result = vkAcquireNextImageKHR(
+ device.device,
+ swapchain,
+ UINT64_MAX,
+ image_available_semaphores[semaphore_index],
+ VK_NULL_HANDLE,
+ &frame_index);
+ switch (present_result) {
+ case VK_ERROR_OUT_OF_DATE_KHR:
+ case VK_SUBOPTIMAL_KHR:
+ needs_recreate = true;
+ return;
+ case VK_SUCCESS:
+ break;
+ default:
+ CHECK_VULKAN(present_result);
+ }
+
+ std::cerr << "starting image layout transition" << std::endl;
+ // Command buffer begins at the very start of the frame
+ // Blit the texture to the swapchain image
+ {
+ // swapchain image layout, undefined -> transfer dst
+ VkImageMemoryBarrier swapchain_image_barrier = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .srcAccessMask = 0,
+ .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = swapchain_images[frame_index],
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .levelCount = 1,
+ .layerCount = 1,
+ },
+ };
+ // src image layout, whatever -> transfer src
+ VkImageMemoryBarrier src_image_barrier = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .srcAccessMask = 0,
+ .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+ .oldLayout = texture->layout,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = texture->image,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .levelCount = 1,
+ .layerCount = 1,
+ },
+ };
+ VkImageMemoryBarrier barriers[2] = {swapchain_image_barrier, src_image_barrier};
+ std::cerr << "starting image layout transition of 2" << std::endl;
+ vkCmdPipelineBarrier(
+ cmd_buf.buffer,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0,
+ 0, nullptr,
+ 0, nullptr,
+ 2, barriers);
+
+ // Blit the texture to the swapchain image
+ VkImageBlit blit = {
+ .srcSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ },
+ .srcOffsets = {
+ {0, 0, 0},
+ {static_cast<int32_t>(texture->extent.width), static_cast<int32_t>(texture->extent.height), 1},
+ },
+ .dstSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ },
+ .dstOffsets = {
+ {0, 0, 0},
+ {static_cast<int32_t>(width), static_cast<int32_t>(height), 1},
+ },
+ };
+ std::cerr << "Starting blit" << std::endl;
+ vkCmdBlitImage(
+ cmd_buf.buffer,
+ texture->image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ swapchain_images[frame_index],
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &blit,
+ VK_FILTER_NEAREST);
+
+ // swapchain image layout, transfer dst -> color attachment
+ // re-use the swapchain_image_barrier
+ swapchain_image_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ swapchain_image_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ swapchain_image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ swapchain_image_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ vkCmdPipelineBarrier(
+ cmd_buf.buffer,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ 0,
+ 0, nullptr,
+ 0, nullptr,
+ 1, &swapchain_image_barrier);
+ }
+
+ std::cerr << "starting render pass" << std::endl;
+ // Render
+ VkRenderPassBeginInfo render_pass_begin_info = {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+ .renderPass = render_pass,
+ .framebuffer = framebuffers[frame_index],
+ .renderArea = {
+ .offset = {0, 0},
+ .extent = {width, height},
+ },
+ .clearValueCount = 0,
+ };
+ vkCmdBeginRenderPass(
+ cmd_buf.buffer,
+ &render_pass_begin_info,
+ VK_SUBPASS_CONTENTS_INLINE);
+ std::cerr << "rendering imgui" << std::endl;
+ ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd_buf.buffer);
+ vkCmdEndRenderPass(cmd_buf.buffer);
+
+ // End command buffer and submit
+ CHECK_VULKAN(vkEndCommandBuffer(cmd_buf.buffer));
+ {
+ VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ VkSubmitInfo submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .waitSemaphoreCount = 1,
+ .pWaitSemaphores = &image_available_semaphores[semaphore_index],
+ .pWaitDstStageMask = &wait_stage,
+ .commandBufferCount = 1,
+ .pCommandBuffers = &cmd_buf.buffer,
+ .signalSemaphoreCount = 1,
+ .pSignalSemaphores = &render_finished_semaphores[semaphore_index],
+ };
+ CHECK_VULKAN(vkQueueSubmit(
+ cmd_buf.queue,
+ 1,
+ &submit_info,
+ VK_NULL_HANDLE));
+ }
+
+ // Present the image to the swapchain
+ VkPresentInfoKHR present_info = {
+ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ .waitSemaphoreCount = 1,
+ .pWaitSemaphores = &render_finished_semaphores[semaphore_index],
+ .swapchainCount = 1,
+ .pSwapchains = &swapchain,
+ .pImageIndices = &frame_index,
+ };
+ present_result = vkQueuePresentKHR(device.graphics_queue, &present_info);
+
+ switch (present_result) {
+ case VK_ERROR_OUT_OF_DATE_KHR:
+ case VK_SUBOPTIMAL_KHR:
+ needs_recreate = true;
+ case VK_SUCCESS:
+ break;
+ default:
+ CHECK_VULKAN(present_result);
+ }
+
+ // Rotate the semaphore index
+ semaphore_index = (semaphore_index + 1) % SWAPCHAIN_IMAGE_COUNT;
+}
+
Swapchain::~Swapchain() {
ImGui_ImplVulkan_Shutdown();
for (uint32_t i = 0; i < SWAPCHAIN_IMAGE_COUNT; i++) {
vkDestroyFramebuffer(device.device, framebuffers[i], nullptr);
vkDestroyImageView(device.device, swapchain_image_views[i], nullptr);
+ vkDestroySemaphore(device.device, image_available_semaphores[i], nullptr);
+ vkDestroySemaphore(device.device, render_finished_semaphores[i], nullptr);
}
vkDestroyDescriptorPool(device.device, descriptor_pool, nullptr);
vkDestroySwapchainKHR(device.device, swapchain, nullptr);
vkDestroyRenderPass(device.device, render_pass, nullptr);
vkDestroySurfaceKHR(device.instance, surface, nullptr);
+
+ upload_texture.reset();
}
} // namespace iris \ No newline at end of file