From e5eed5bdfa01cf549436c6001eaf334d266acc40 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Sat, 14 Sep 2024 22:38:51 -0700 Subject: fix lifetime problem --- src/app.cpp | 20 +++---- src/vulkan_helper.cpp | 133 ++++++++++++++++++++++++++++++++++++++++------- src/vulkan_helper.h | 20 +++++-- src/vulkan_swapchain.cpp | 33 +++++++----- src/vulkan_swapchain.h | 2 +- 5 files changed, 156 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/app.cpp b/src/app.cpp index 6148e04..f48edd9 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -16,7 +16,7 @@ #include int main(int argc, char** argv) { - argparse::ArgumentParser program("IrisRenderer"); + argparse::ArgumentParser program("Iris Renderer"); program.add_argument("width") .help("display width of the window") .scan<'i', int>(); @@ -48,15 +48,11 @@ int main(int argc, char** argv) { return -1; } auto glfw_extensions = get_glfw_instance_extensions(); - for (const auto& extension : glfw_extensions) { - std::cerr << "GLFW extension: " << extension << std::endl; - } - std::vector layers; - iris::Device device({}, glfw_extensions); + iris::Device device(layers, glfw_extensions); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - auto window = glfwCreateWindow(window_width, window_height, "IrisRenderer", nullptr, nullptr); + auto window = glfwCreateWindow(window_width, window_height, "Iris Renderer", nullptr, nullptr); if (window == nullptr) { std::cerr << "Failed to create GLFW window" << std::endl; abort(); @@ -66,7 +62,9 @@ int main(int argc, char** argv) { iris::Texture2D debug_texture = device.create_texture_from_image( "assets/debug.png", VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT, VmaAllocationCreateInfo { .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, .usage = VMA_MEMORY_USAGE_AUTO, @@ -74,7 +72,6 @@ int main(int argc, char** argv) { // end load debug image auto swapchain = iris::Swapchain(window, device, window_width, window_height); - std::cerr << "Swapchain created" << std::endl; while (!glfwWindowShouldClose(swapchain.window)) { glfwPollEvents(); @@ -92,19 +89,16 @@ int main(int argc, char** argv) { swapchain.needs_recreate = false; } - std::cerr << "Rendering frame" << std::endl; ImGui_ImplVulkan_NewFrame(); ImGui_ImplGlfw_NewFrame(); swapchain.start_frame(); - std::cerr << "Frame started" << std::endl; ImGui::NewFrame(); ImGui::ShowDemoWindow(); ImGui::Render(); - std::cerr << "ImGui rendered" << std::endl; swapchain.display(debug_texture); - std::cerr << "Frame displayed" << std::endl; } + debug_texture->release(); ImGui_ImplVulkan_Shutdown(); glfwDestroyWindow(swapchain.window); diff --git a/src/vulkan_helper.cpp b/src/vulkan_helper.cpp index 339b9c0..69617c4 100644 --- a/src/vulkan_helper.cpp +++ b/src/vulkan_helper.cpp @@ -12,12 +12,33 @@ #include #ifdef USE_VULKAN_VALIDATION_LAYERS -static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) +static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData) { (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage); return VK_FALSE; } + +VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) +{ + (void) messageSeverity; + (void) messageType; + (void) pUserData; + std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; + return VK_FALSE; +} #endif namespace iris { @@ -25,20 +46,24 @@ namespace iris { Device::Device(std::vector layers, std::vector instance_extensions) { VkApplicationInfo app_info = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = "IrisRenderer", + .pApplicationName = "Iris Renderer", .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .pEngineName = "No Engine", .engineVersion = VK_MAKE_VERSION(1, 0, 0), .apiVersion = VK_API_VERSION_1_3, }; +#ifdef USE_VULKAN_VALIDATION_LAYERS + layers.push_back("VK_LAYER_KHRONOS_validation"); + instance_extensions.push_back("VK_EXT_debug_utils"); +#endif + // Create the Vulkan instance uint32_t enabled_layer_count = layers.size(); std::vector layers_cstr; for (const auto& layer : layers) { layers_cstr.push_back(layer.c_str()); } - uint32_t enabled_extension_count = instance_extensions.size(); std::vector instance_extensions_cstr; for (const auto& extension : instance_extensions) { @@ -59,16 +84,32 @@ Device::Device(std::vector layers, std::vector instanc &instance)); #ifdef USE_VULKAN_VALIDATION_LAYERS - layers.push_back("VK_LAYER_KHRONOS_validation"); - auto vkCreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); + auto vkCreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT) + vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); if (vkCreateDebugReportCallback) { VkDebugReportCallbackCreateInfoEXT debug_report_create_info = { .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, - .flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, + .flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | + VK_DEBUG_REPORT_WARNING_BIT_EXT | + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, .pfnCallback = debug_report, }; CHECK_VULKAN(vkCreateDebugReportCallback(instance, &debug_report_create_info, nullptr, &debugReportCallback)); } + auto vkCreateDebugUtilsMessenger = (PFN_vkCreateDebugUtilsMessengerEXT) + vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); + if (vkCreateDebugUtilsMessenger) { + VkDebugUtilsMessengerCreateInfoEXT debug_utils_create_info = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = debug_callback, + }; + CHECK_VULKAN(vkCreateDebugUtilsMessenger(instance, &debug_utils_create_info, nullptr, &debugUtilsMessenger)); + } #endif // Enumerate and select the physical device @@ -196,6 +237,7 @@ CommandBuffer::CommandBuffer(VkDevice device, { VkCommandPoolCreateInfo pool_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = queue_family_index, // TODO: query capabilities to find a proper queue index }; CHECK_VULKAN(vkCreateCommandPool( @@ -225,7 +267,41 @@ CommandBuffer::CommandBuffer(VkDevice device, &fence)); } -CommandBuffer::~CommandBuffer() { +AsyncCommandBuffer::AsyncCommandBuffer(VkDevice device, + uint32_t queue_family_index, + VkQueue queue) + : device(device), queue(queue) +{ + VkCommandPoolCreateInfo pool_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = queue_family_index, // TODO: query capabilities to find a proper queue index + }; + CHECK_VULKAN(vkCreateCommandPool( + device, + &pool_info, + VK_NULL_HANDLE, + &this->pool)); + + VkCommandBufferAllocateInfo buffer_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = this->pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + CHECK_VULKAN(vkAllocateCommandBuffers( + device, + &buffer_info, + &buffer)); +} + +void AsyncCommandBuffer::destroy() { + vkFreeCommandBuffers(device, pool, 1, &buffer); + vkDestroyCommandPool(device, pool, VK_NULL_HANDLE); +} + + +void CommandBuffer::destroy() { vkDestroyFence(device, fence, VK_NULL_HANDLE); vkFreeCommandBuffers(device, pool, 1, &buffer); vkDestroyCommandPool(device, pool, VK_NULL_HANDLE); @@ -235,6 +311,10 @@ CommandBuffer Device::create_command_buffer() { return CommandBuffer(device, main_queue_family_index, graphics_queue); } +AsyncCommandBuffer Device::create_async_command_buffer() { + return AsyncCommandBuffer(device, main_queue_family_index, graphics_queue); +} + void CommandBuffer::begin(VkCommandBufferUsageFlags flags) { CHECK_VULKAN(vkResetFences(device, 1, &fence)); CHECK_VULKAN(vkResetCommandPool(device, pool, 0u)); @@ -284,8 +364,12 @@ void Buffer_t::unmap() { } } -Buffer_t::~Buffer_t() { - vmaDestroyBuffer(allocator, buffer, allocation); +void Buffer_t::release() { + if (buffer != VK_NULL_HANDLE) { + std::cerr << "Destroying buffer: 0x" << std::hex << (uint64_t)buffer << std::endl; + vmaDestroyBuffer(allocator, buffer, allocation); + buffer = VK_NULL_HANDLE; + } } Buffer_t Device::create_buffer_raw(VkDeviceSize size, @@ -319,9 +403,12 @@ Buffer Device::create_buffer(VkDeviceSize size, return std::make_shared(create_buffer_raw(size, usage, create_info)); } -Texture2D_t::~Texture2D_t() { - vmaDestroyImage(allocator, image, allocation); - // TODO: optionally destroy image view, if created +void Texture2D_t::release() { + if (image != VK_NULL_HANDLE) { + std::cerr << "Destroying image: 0x" << std::hex << (uint64_t)image << std::endl; + vmaDestroyImage(allocator, image, allocation); + image = VK_NULL_HANDLE; + } } Texture2D_t Device::create_texture_raw(VkExtent2D extent, @@ -353,6 +440,7 @@ Texture2D_t Device::create_texture_raw(VkExtent2D extent, &texture.image, &texture.allocation, VK_NULL_HANDLE)); + std::cerr << "Created image: 0x" << std::hex << (uint64_t)texture.image << std::endl; return texture; } @@ -361,7 +449,9 @@ Texture2D Device::create_texture(VkExtent2D extent, VkImageUsageFlags usage, VmaAllocationCreateInfo create_info) { - return std::make_shared(create_texture_raw(extent, format, usage, create_info)); + auto t = std::make_shared(create_texture_raw(extent, format, usage, create_info)); + std::cerr << "Before create texture terminates" << std::endl; + return t; } Texture2D Device::create_texture_from_image(const char* filename, @@ -393,7 +483,7 @@ Texture2D Device::create_texture_from_image(const char* filename, stbi_image_free(pixels); VkExtent2D extent = {static_cast(width), static_cast(height)}; - Texture2D_t texture = create_texture_raw(extent, format, usage, create_info); + Texture2D texture = create_texture(extent, format, usage, create_info); // Transit image layout for copying { @@ -403,15 +493,16 @@ Texture2D Device::create_texture_from_image(const char* filename, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; CHECK_VULKAN(vkBeginCommandBuffer(cmd_buf.buffer, &begin_info)); + std::cerr << "Image layout transition for 0x" << std::hex << (uint64_t)texture->image << std::endl; VkImageMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = 0, + .srcAccessMask = VK_ACCESS_NONE, .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 = texture.image, + .image = texture->image, .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, @@ -460,7 +551,7 @@ Texture2D Device::create_texture_from_image(const char* filename, vkCmdCopyBufferToImage( cmd_buf.buffer, staging_buf.buffer, - texture.image, + texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); @@ -490,7 +581,7 @@ Texture2D Device::create_texture_from_image(const char* filename, .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = texture.image, + .image = texture->image, .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, @@ -514,8 +605,10 @@ Texture2D Device::create_texture_from_image(const char* filename, CHECK_VULKAN(vkQueueSubmit(graphics_queue, 1, &submit_info, cmd_buf.fence)); CHECK_VULKAN(vkWaitForFences(cmd_buf.device, 1, &cmd_buf.fence, VK_TRUE, std::numeric_limits::max())); } - texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - return std::make_shared(texture); + texture->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + std::cerr << "Image layout transition done" << std::endl; + staging_buf.release(); + return texture; } } // namespace iris \ No newline at end of file diff --git a/src/vulkan_helper.h b/src/vulkan_helper.h index ebdd691..c2b1c8c 100644 --- a/src/vulkan_helper.h +++ b/src/vulkan_helper.h @@ -23,14 +23,13 @@ struct Buffer_t { VkBuffer buffer; VmaAllocator allocator; VmaAllocation allocation; - VkBufferUsageFlags flags; VkDeviceSize size; void *mapped_data = nullptr; - ~Buffer_t(); void* map(); void unmap(); + void release(); }; typedef std::shared_ptr Buffer; @@ -45,7 +44,7 @@ struct Texture2D_t { VkImageUsageFlags flags; VkExtent2D extent; - ~Texture2D_t(); + void release(); }; typedef std::shared_ptr Texture2D; @@ -60,12 +59,21 @@ struct CommandBuffer { VkQueue queue; CommandBuffer(VkDevice device, uint32_t queue_family_index, VkQueue queue); - ~CommandBuffer(); - + void destroy(); void begin(VkCommandBufferUsageFlags flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); void submit_sync(); }; +struct AsyncCommandBuffer { + VkDevice device; + VkCommandPool pool; + VkCommandBuffer buffer; + VkQueue queue; + + AsyncCommandBuffer(VkDevice device, uint32_t queue_family_index, VkQueue queue); + void destroy(); +}; + struct Device { VkInstance instance; VkPhysicalDevice physical_device; @@ -75,6 +83,7 @@ struct Device { VmaAllocator allocator; #ifdef USE_VULKAN_VALIDATION_LAYERS VkDebugReportCallbackEXT debugReportCallback; + VkDebugUtilsMessengerEXT debugUtilsMessenger; #endif Device() = delete; @@ -122,6 +131,7 @@ struct Device { }); CommandBuffer create_command_buffer(); + AsyncCommandBuffer create_async_command_buffer(); }; } // namespace iris \ No newline at end of file diff --git a/src/vulkan_swapchain.cpp b/src/vulkan_swapchain.cpp index 41d27a5..7916a3b 100644 --- a/src/vulkan_swapchain.cpp +++ b/src/vulkan_swapchain.cpp @@ -152,7 +152,7 @@ Swapchain::Swapchain(GLFWwindow *window, , window(window) , width(width) , height(height) - , cmd_buf(device.create_command_buffer()) + , cmd_buf(device.create_async_command_buffer()) { if (!glfwVulkanSupported()) { std::cerr << "GLFW failed to find Vulkan support" << std::endl; @@ -160,7 +160,6 @@ Swapchain::Swapchain(GLFWwindow *window, abort(); } - std::cerr << "Creating surface" << std::endl; // Create the surface CHECK_VULKAN(glfwCreateWindowSurface( device.instance, @@ -326,7 +325,6 @@ void Swapchain::start_frame() { } void Swapchain::display(Texture2D& texture) { - std::cerr << "Displaying" << std::endl; VkResult present_result = vkAcquireNextImageKHR( device.device, swapchain, @@ -345,14 +343,13 @@ void Swapchain::display(Texture2D& texture) { 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, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -368,7 +365,7 @@ void Swapchain::display(Texture2D& texture) { // src image layout, whatever -> transfer src VkImageMemoryBarrier src_image_barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = 0, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, .oldLayout = texture->layout, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -381,8 +378,9 @@ void Swapchain::display(Texture2D& texture) { .layerCount = 1, }, }; - VkImageMemoryBarrier barriers[2] = {swapchain_image_barrier, src_image_barrier}; - std::cerr << "starting image layout transition of 2" << std::endl; + VkImageMemoryBarrier barriers[] = {src_image_barrier, swapchain_image_barrier}; + uint32_t barrier_count = sizeof(barriers) / sizeof(VkImageMemoryBarrier); + vkCmdPipelineBarrier( cmd_buf.buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, @@ -390,7 +388,7 @@ void Swapchain::display(Texture2D& texture) { 0, 0, nullptr, 0, nullptr, - 2, barriers); + barrier_count, barriers); // Blit the texture to the swapchain image VkImageBlit blit = { @@ -415,7 +413,6 @@ void Swapchain::display(Texture2D& texture) { {static_cast(width), static_cast(height), 1}, }, }; - std::cerr << "Starting blit" << std::endl; vkCmdBlitImage( cmd_buf.buffer, texture->image, @@ -435,15 +432,26 @@ void Swapchain::display(Texture2D& texture) { VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; vkCmdPipelineBarrier( cmd_buf.buffer, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &swapchain_image_barrier); + src_image_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + src_image_barrier.newLayout = texture->layout; + src_image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + src_image_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + vkCmdPipelineBarrier( + cmd_buf.buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &src_image_barrier); } - std::cerr << "starting render pass" << std::endl; // Render VkRenderPassBeginInfo render_pass_begin_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, @@ -459,7 +467,6 @@ void Swapchain::display(Texture2D& texture) { 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); diff --git a/src/vulkan_swapchain.h b/src/vulkan_swapchain.h index b15028f..257840a 100644 --- a/src/vulkan_swapchain.h +++ b/src/vulkan_swapchain.h @@ -28,7 +28,7 @@ struct Swapchain { VkFramebuffer framebuffers[SWAPCHAIN_IMAGE_COUNT]; VkSemaphore image_available_semaphores[SWAPCHAIN_IMAGE_COUNT]; VkSemaphore render_finished_semaphores[SWAPCHAIN_IMAGE_COUNT]; - CommandBuffer cmd_buf; + AsyncCommandBuffer cmd_buf; Texture2D upload_texture; -- cgit v1.2.3-70-g09d2