From 6185c081c1a6ec13b54eab6a12ff72814cf3addb Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Tue, 1 Oct 2024 17:08:41 -0700 Subject: Fix vulkan validation error --- src/app.cpp | 10 ++-- src/vulkan_helper.cpp | 122 +++++++++++++++++++++++++---------------------- src/vulkan_helper.h | 26 ++++------ src/vulkan_swapchain.cpp | 44 +++++++++-------- src/vulkan_swapchain.h | 2 +- 5 files changed, 108 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/src/app.cpp b/src/app.cpp index f48edd9..11a219d 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -4,6 +4,8 @@ #include "imgui_impl_vulkan.h" #include "argparse/argparse.hpp" #include +#include +#include #include #include #include @@ -16,6 +18,7 @@ #include int main(int argc, char** argv) { + spdlog::cfg::load_env_levels(); argparse::ArgumentParser program("Iris Renderer"); program.add_argument("width") .help("display width of the window") @@ -39,9 +42,9 @@ int main(int argc, char** argv) { const char* description = nullptr; glfwGetError(&description); if (description != nullptr) { - std::cerr << "Error: " << description << std::endl; + spdlog::critical("Failed to initialize GLFW: {}", description); } else { - std::cerr << "Failed to initialize GLFW" << std::endl; + spdlog::critical("Failed to initialize GLFW"); } glfwTerminate(); @@ -54,7 +57,7 @@ int main(int argc, char** argv) { glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); auto window = glfwCreateWindow(window_width, window_height, "Iris Renderer", nullptr, nullptr); if (window == nullptr) { - std::cerr << "Failed to create GLFW window" << std::endl; + spdlog::critical("Failed to create GLFW window"); abort(); } @@ -103,6 +106,7 @@ int main(int argc, char** argv) { glfwDestroyWindow(swapchain.window); glfwTerminate(); + swapchain.release(); device.destroy(); return 0; diff --git a/src/vulkan_helper.cpp b/src/vulkan_helper.cpp index 69617c4..f39d867 100644 --- a/src/vulkan_helper.cpp +++ b/src/vulkan_helper.cpp @@ -1,12 +1,12 @@ #include "vulkan_helper.h" #include "vulkan/vulkan_core.h" #include +#include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include #include #include -#include #include #define VMA_IMPLEMENTATION #include @@ -23,7 +23,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report( 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); + spdlog::debug("[vulkan] Debug report from ObjectType: {}\nMessage: {}\n\n", (uint32_t)objectType, pMessage); return VK_FALSE; } @@ -36,7 +36,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( (void) messageSeverity; (void) messageType; (void) pUserData; - std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; + spdlog::error("{}", pCallbackData->pMessage); return VK_FALSE; } #endif @@ -151,8 +151,7 @@ Device::Device(std::vector layers, std::vector instanc } if (!has_raytracing || !has_acceleration_structure) { - // TODO throw an exception - std::cerr << "Physical device does not support ray tracing extensions" << std::endl; + spdlog::critical("Physical device does not support ray tracing extensions"); abort(); } } @@ -225,6 +224,19 @@ Device::Device(std::vector layers, std::vector instanc // not handled by RAII, manually call at the end. void Device::destroy() { +#ifdef USE_VULKAN_VALIDATION_LAYERS + auto vkDestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT) + vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); + if (vkDestroyDebugReportCallback) { + vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr); + } + auto vkDestroyDebugUtilsMessenger = (PFN_vkDestroyDebugUtilsMessengerEXT) + vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); + if (vkDestroyDebugUtilsMessenger) { + vkDestroyDebugUtilsMessenger(instance, debugUtilsMessenger, nullptr); + } +#endif + vmaDestroyAllocator(allocator); vkDestroyDevice(device, VK_NULL_HANDLE); vkDestroyInstance(instance, VK_NULL_HANDLE); @@ -265,6 +277,7 @@ CommandBuffer::CommandBuffer(VkDevice device, &fence_info, VK_NULL_HANDLE, &fence)); + spdlog::debug("Created command buffer: 0x{:x}", (uint64_t)buffer); } AsyncCommandBuffer::AsyncCommandBuffer(VkDevice device, @@ -293,11 +306,23 @@ AsyncCommandBuffer::AsyncCommandBuffer(VkDevice device, device, &buffer_info, &buffer)); + + VkFenceCreateInfo fence_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + }; + CHECK_VULKAN(vkCreateFence( + device, + &fence_info, + VK_NULL_HANDLE, + &fence)); + spdlog::debug("Created async command buffer: 0x{:x}", (uint64_t)buffer); } void AsyncCommandBuffer::destroy() { + vkDestroyFence(device, fence, VK_NULL_HANDLE); vkFreeCommandBuffers(device, pool, 1, &buffer); vkDestroyCommandPool(device, pool, VK_NULL_HANDLE); + spdlog::debug("Destroyed async command buffer: 0x{:x}", (uint64_t)buffer); } @@ -305,6 +330,7 @@ void CommandBuffer::destroy() { vkDestroyFence(device, fence, VK_NULL_HANDLE); vkFreeCommandBuffers(device, pool, 1, &buffer); vkDestroyCommandPool(device, pool, VK_NULL_HANDLE); + spdlog::debug("Destroyed command buffer: 0x{:x}", (uint64_t)buffer); } CommandBuffer Device::create_command_buffer() { @@ -366,55 +392,51 @@ void Buffer_t::unmap() { void Buffer_t::release() { if (buffer != VK_NULL_HANDLE) { - std::cerr << "Destroying buffer: 0x" << std::hex << (uint64_t)buffer << std::endl; + spdlog::debug("Destroying buffer: 0x{:x}", (uint64_t)buffer); + vkDeviceWaitIdle(device); vmaDestroyBuffer(allocator, buffer, allocation); buffer = VK_NULL_HANDLE; } } -Buffer_t Device::create_buffer_raw(VkDeviceSize size, - VkBufferUsageFlags usage, - VmaAllocationCreateInfo create_info) +Buffer Device::create_buffer(VkDeviceSize size, + VkBufferUsageFlags usage, + VmaAllocationCreateInfo create_info) { VkBufferCreateInfo buffer_info = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .size = size, .usage = usage, }; - Buffer_t buffer = { - .allocator = this->allocator, - .flags = usage, - .size = size, - }; + Buffer buffer = std::make_shared(); + buffer->device = this->device; + buffer->allocator = this->allocator; + buffer->flags = usage; + buffer->size = size; CHECK_VULKAN(vmaCreateBuffer( allocator, &buffer_info, &create_info, - &buffer.buffer, - &buffer.allocation, + &buffer->buffer, + &buffer->allocation, VK_NULL_HANDLE)); + spdlog::debug("Created buffer: 0x{:x}", (uint64_t)buffer->buffer); return buffer; } -Buffer Device::create_buffer(VkDeviceSize size, - VkBufferUsageFlags usage, - VmaAllocationCreateInfo create_info) -{ - return std::make_shared(create_buffer_raw(size, usage, create_info)); -} - void Texture2D_t::release() { if (image != VK_NULL_HANDLE) { - std::cerr << "Destroying image: 0x" << std::hex << (uint64_t)image << std::endl; + spdlog::debug("Destroying image: 0x{:x}", (uint64_t)image); + vkDeviceWaitIdle(device); vmaDestroyImage(allocator, image, allocation); image = VK_NULL_HANDLE; } } -Texture2D_t Device::create_texture_raw(VkExtent2D extent, - VkFormat format, - VkImageUsageFlags usage, - VmaAllocationCreateInfo create_info) +Texture2D Device::create_texture(VkExtent2D extent, + VkFormat format, + VkImageUsageFlags usage, + VmaAllocationCreateInfo create_info) { VkImageCreateInfo image_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, @@ -427,33 +449,25 @@ Texture2D_t Device::create_texture_raw(VkExtent2D extent, .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = usage, }; - Texture2D_t texture = { - .allocator = this->allocator, - .layout = VK_IMAGE_LAYOUT_UNDEFINED, - .flags = usage, - .extent = extent, - }; + + Texture2D texture = std::make_shared(); + texture->device = this->device; + texture->allocator = this->allocator; + texture->layout = VK_IMAGE_LAYOUT_UNDEFINED; + texture->flags = usage; + texture->extent = extent; + CHECK_VULKAN(vmaCreateImage( allocator, &image_info, &create_info, - &texture.image, - &texture.allocation, + &texture->image, + &texture->allocation, VK_NULL_HANDLE)); - std::cerr << "Created image: 0x" << std::hex << (uint64_t)texture.image << std::endl; + spdlog::debug("Created image: 0x{:x}", (uint64_t)texture->image); return texture; } -Texture2D Device::create_texture(VkExtent2D extent, - VkFormat format, - VkImageUsageFlags usage, - VmaAllocationCreateInfo 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, VkFormat format, VkImageUsageFlags usage, @@ -461,13 +475,12 @@ Texture2D Device::create_texture_from_image(const char* filename, int width, height, channels; stbi_uc* pixels = stbi_load(filename, &width, &height, &channels, STBI_rgb_alpha); if (pixels == nullptr) { - // TODO throw an exception - std::cerr << "Failed to load image: " << filename << std::endl; + spdlog::critical("Failed to load image: {}", filename); abort(); } // destroy after use, don't need to wrap with shared_ptr - auto staging_buf = create_buffer_raw( + auto staging_buf = create_buffer( width * height * 4, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VmaAllocationCreateInfo { @@ -476,10 +489,10 @@ Texture2D Device::create_texture_from_image(const char* filename, .usage = VMA_MEMORY_USAGE_AUTO, }); std::memcpy( - staging_buf.map(), + staging_buf->map(), pixels, width * height * 4); - staging_buf.unmap(); + staging_buf->unmap(); stbi_image_free(pixels); VkExtent2D extent = {static_cast(width), static_cast(height)}; @@ -493,7 +506,6 @@ 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 = VK_ACCESS_NONE, @@ -550,7 +562,7 @@ Texture2D Device::create_texture_from_image(const char* filename, }; vkCmdCopyBufferToImage( cmd_buf.buffer, - staging_buf.buffer, + staging_buf->buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, @@ -606,8 +618,6 @@ Texture2D Device::create_texture_from_image(const char* filename, CHECK_VULKAN(vkWaitForFences(cmd_buf.device, 1, &cmd_buf.fence, VK_TRUE, std::numeric_limits::max())); } texture->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - std::cerr << "Image layout transition done" << std::endl; - staging_buf.release(); return texture; } diff --git a/src/vulkan_helper.h b/src/vulkan_helper.h index c2b1c8c..d8c9c32 100644 --- a/src/vulkan_helper.h +++ b/src/vulkan_helper.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -11,8 +12,7 @@ do { \ VkResult res = result; \ if (res != VK_SUCCESS) { \ - /* TODO: throw error instead of returning */ \ - std::cerr << "Vulkan error: " << string_VkResult(res) << std::endl; \ + spdlog::error("Vulkan error: {}", string_VkResult(res)); \ abort(); \ } \ } while (0) @@ -21,6 +21,7 @@ namespace iris { struct Buffer_t { VkBuffer buffer; + VkDevice device; VmaAllocator allocator; VmaAllocation allocation; VkBufferUsageFlags flags; @@ -30,12 +31,14 @@ struct Buffer_t { void* map(); void unmap(); void release(); + ~Buffer_t() { release(); } }; typedef std::shared_ptr Buffer; struct Texture2D_t { VkImage image; + VkDevice device; VmaAllocator allocator; VmaAllocation allocation; VkImageView image_view; @@ -45,6 +48,7 @@ struct Texture2D_t { VkExtent2D extent; void release(); + ~Texture2D_t() { release(); } }; typedef std::shared_ptr Texture2D; @@ -62,16 +66,19 @@ struct CommandBuffer { void destroy(); void begin(VkCommandBufferUsageFlags flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); void submit_sync(); + ~CommandBuffer() { destroy(); } }; struct AsyncCommandBuffer { VkDevice device; VkCommandPool pool; VkCommandBuffer buffer; + VkFence fence; VkQueue queue; AsyncCommandBuffer(VkDevice device, uint32_t queue_family_index, VkQueue queue); void destroy(); + ~AsyncCommandBuffer() { destroy(); } }; struct Device { @@ -92,21 +99,6 @@ struct Device { std::vector instance_extensions); void destroy(); - Buffer_t create_buffer_raw( - VkDeviceSize size, - VkBufferUsageFlags usage, - VmaAllocationCreateInfo create_info = { - .usage = VMA_MEMORY_USAGE_AUTO, - }); - - Texture2D_t create_texture_raw( - VkExtent2D extent, - VkFormat format, - VkImageUsageFlags usage, - VmaAllocationCreateInfo create_info = { - .usage = VMA_MEMORY_USAGE_AUTO, - }); - Buffer create_buffer( VkDeviceSize size, VkBufferUsageFlags usage, diff --git a/src/vulkan_swapchain.cpp b/src/vulkan_swapchain.cpp index 7916a3b..21948c1 100644 --- a/src/vulkan_swapchain.cpp +++ b/src/vulkan_swapchain.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -77,8 +77,7 @@ void Swapchain::resize(uint32_t new_width, uint32_t new_height) { &image_count, nullptr)); if (image_count > SWAPCHAIN_IMAGE_COUNT) { - // TODO throw an exception - std::cerr << "Swapchain image count is greater than expected" << std::endl; + spdlog::critical("Swapchain image count is greater than expected"); abort(); } CHECK_VULKAN(vkGetSwapchainImagesKHR( @@ -134,6 +133,9 @@ void Swapchain::resize(uint32_t new_width, uint32_t new_height) { &framebuffers[i])); } + if (upload_texture) { + upload_texture->release(); + } upload_texture = device.create_texture( {width, height}, VK_FORMAT_B8G8R8A8_UNORM, @@ -155,8 +157,7 @@ Swapchain::Swapchain(GLFWwindow *window, , cmd_buf(device.create_async_command_buffer()) { if (!glfwVulkanSupported()) { - std::cerr << "GLFW failed to find Vulkan support" << std::endl; - // TODO throw an exception + spdlog::critical("GLFW failed to find Vulkan support"); abort(); } @@ -176,8 +177,7 @@ Swapchain::Swapchain(GLFWwindow *window, surface, &supported)); if (supported != VK_TRUE) { - // TODO throw an exception - std::cerr << "Surface does not support presentation" << std::endl; + spdlog::critical("Surface does not support presentation"); abort(); } @@ -188,8 +188,7 @@ Swapchain::Swapchain(GLFWwindow *window, &surface_capabilities)); if (surface_capabilities.maxImageCount < SWAPCHAIN_IMAGE_COUNT) { - // TODO throw an exception - std::cerr << "Surface does not support enough images" << std::endl; + spdlog::critical("Surface does not support enough images"); abort(); } } @@ -280,6 +279,7 @@ Swapchain::Swapchain(GLFWwindow *window, }; VkDescriptorPoolCreateInfo pool_info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, .maxSets = 1, .poolSizeCount = 1, .pPoolSizes = &pool_size, @@ -317,11 +317,17 @@ Swapchain::Swapchain(GLFWwindow *window, } void Swapchain::start_frame() { + spdlog::trace("Starting frame {}", frame_index); VkCommandBufferBeginInfo begin_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; + + if (vkGetFenceStatus(device.device, cmd_buf.fence) == VK_NOT_READY) { + vkWaitForFences(device.device, 1, &cmd_buf.fence, VK_TRUE, 2e6); + } CHECK_VULKAN(vkBeginCommandBuffer(cmd_buf.buffer, &begin_info)); + vkResetFences(device.device, 1, &cmd_buf.fence); } void Swapchain::display(Texture2D& texture) { @@ -331,7 +337,7 @@ void Swapchain::display(Texture2D& texture) { UINT64_MAX, image_available_semaphores[semaphore_index], VK_NULL_HANDLE, - &frame_index); + &semaphore_index); switch (present_result) { case VK_ERROR_OUT_OF_DATE_KHR: case VK_SUBOPTIMAL_KHR: @@ -355,7 +361,7 @@ void Swapchain::display(Texture2D& texture) { .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = swapchain_images[frame_index], + .image = swapchain_images[semaphore_index], .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, @@ -417,7 +423,7 @@ void Swapchain::display(Texture2D& texture) { cmd_buf.buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - swapchain_images[frame_index], + swapchain_images[semaphore_index], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, @@ -456,7 +462,7 @@ void Swapchain::display(Texture2D& texture) { VkRenderPassBeginInfo render_pass_begin_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderPass = render_pass, - .framebuffer = framebuffers[frame_index], + .framebuffer = framebuffers[semaphore_index], .renderArea = { .offset = {0, 0}, .extent = {width, height}, @@ -488,7 +494,7 @@ void Swapchain::display(Texture2D& texture) { cmd_buf.queue, 1, &submit_info, - VK_NULL_HANDLE)); + cmd_buf.fence)); } // Present the image to the swapchain @@ -498,7 +504,7 @@ void Swapchain::display(Texture2D& texture) { .pWaitSemaphores = &render_finished_semaphores[semaphore_index], .swapchainCount = 1, .pSwapchains = &swapchain, - .pImageIndices = &frame_index, + .pImageIndices = &semaphore_index, }; present_result = vkQueuePresentKHR(device.graphics_queue, &present_info); @@ -514,10 +520,12 @@ void Swapchain::display(Texture2D& texture) { // Rotate the semaphore index semaphore_index = (semaphore_index + 1) % SWAPCHAIN_IMAGE_COUNT; + frame_index += 1; } -Swapchain::~Swapchain() { - ImGui_ImplVulkan_Shutdown(); +void Swapchain::release() { + upload_texture->release(); + cmd_buf.destroy(); for (uint32_t i = 0; i < SWAPCHAIN_IMAGE_COUNT; i++) { vkDestroyFramebuffer(device.device, framebuffers[i], nullptr); @@ -530,8 +538,6 @@ Swapchain::~Swapchain() { 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 diff --git a/src/vulkan_swapchain.h b/src/vulkan_swapchain.h index 257840a..1cd270c 100644 --- a/src/vulkan_swapchain.h +++ b/src/vulkan_swapchain.h @@ -39,8 +39,8 @@ struct Swapchain { void resize(uint32_t new_width, uint32_t new_height); void start_frame(); void display(Texture2D &texture); + void release(); Swapchain(GLFWwindow *window, iris::Device device, uint32_t width, uint32_t height); - ~Swapchain(); }; } // namespace iris \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 4bb8fd5ac5c07e8756ae097e7f5d7f34697bc914 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Tue, 1 Oct 2024 17:54:43 -0700 Subject: fix command buffer release issue --- src/vulkan_helper.cpp | 66 +++++++++--------------------------------------- src/vulkan_helper.h | 13 ---------- src/vulkan_swapchain.cpp | 2 +- src/vulkan_swapchain.h | 2 +- 4 files changed, 14 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/vulkan_helper.cpp b/src/vulkan_helper.cpp index f39d867..567d414 100644 --- a/src/vulkan_helper.cpp +++ b/src/vulkan_helper.cpp @@ -278,69 +278,27 @@ CommandBuffer::CommandBuffer(VkDevice device, VK_NULL_HANDLE, &fence)); spdlog::debug("Created command buffer: 0x{:x}", (uint64_t)buffer); + spdlog::debug("Created fence: 0x{:x}", (uint64_t)fence); } -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)); - - VkFenceCreateInfo fence_info = { - .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - }; - CHECK_VULKAN(vkCreateFence( - device, - &fence_info, - VK_NULL_HANDLE, - &fence)); - spdlog::debug("Created async command buffer: 0x{:x}", (uint64_t)buffer); -} - -void AsyncCommandBuffer::destroy() { - vkDestroyFence(device, fence, VK_NULL_HANDLE); - vkFreeCommandBuffers(device, pool, 1, &buffer); - vkDestroyCommandPool(device, pool, VK_NULL_HANDLE); - spdlog::debug("Destroyed async command buffer: 0x{:x}", (uint64_t)buffer); -} - - void CommandBuffer::destroy() { - vkDestroyFence(device, fence, VK_NULL_HANDLE); - vkFreeCommandBuffers(device, pool, 1, &buffer); - vkDestroyCommandPool(device, pool, VK_NULL_HANDLE); - spdlog::debug("Destroyed command buffer: 0x{:x}", (uint64_t)buffer); + if (fence != VK_NULL_HANDLE) { + vkDestroyFence(device, fence, VK_NULL_HANDLE); + vkFreeCommandBuffers(device, pool, 1, &buffer); + vkDestroyCommandPool(device, pool, VK_NULL_HANDLE); + + spdlog::debug("Destroyed fence: 0x{:x}", (uint64_t)fence); + spdlog::debug("Destroyed command buffer: 0x{:x}", (uint64_t)buffer); + fence = VK_NULL_HANDLE; + buffer = VK_NULL_HANDLE; + pool = VK_NULL_HANDLE; + } } 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)); diff --git a/src/vulkan_helper.h b/src/vulkan_helper.h index d8c9c32..6dbf0b7 100644 --- a/src/vulkan_helper.h +++ b/src/vulkan_helper.h @@ -69,18 +69,6 @@ struct CommandBuffer { ~CommandBuffer() { destroy(); } }; -struct AsyncCommandBuffer { - VkDevice device; - VkCommandPool pool; - VkCommandBuffer buffer; - VkFence fence; - VkQueue queue; - - AsyncCommandBuffer(VkDevice device, uint32_t queue_family_index, VkQueue queue); - void destroy(); - ~AsyncCommandBuffer() { destroy(); } -}; - struct Device { VkInstance instance; VkPhysicalDevice physical_device; @@ -123,7 +111,6 @@ 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 21948c1..c38e9f6 100644 --- a/src/vulkan_swapchain.cpp +++ b/src/vulkan_swapchain.cpp @@ -154,7 +154,7 @@ Swapchain::Swapchain(GLFWwindow *window, , window(window) , width(width) , height(height) - , cmd_buf(device.create_async_command_buffer()) + , cmd_buf(device.create_command_buffer()) { if (!glfwVulkanSupported()) { spdlog::critical("GLFW failed to find Vulkan support"); diff --git a/src/vulkan_swapchain.h b/src/vulkan_swapchain.h index 1cd270c..381c5b0 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]; - AsyncCommandBuffer cmd_buf; + CommandBuffer cmd_buf; Texture2D upload_texture; -- cgit v1.2.3-70-g09d2 From e59529d3f55b9128f798a7f02a7288f96bdaf9a4 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Thu, 3 Oct 2024 19:49:47 -0700 Subject: use xmake build & scene load wip --- .gitignore | 1 + .gitmodules | 3 ++ CMakeLists.txt | 5 ++- ext/glm | 1 + src/gltf_loader.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ src/gltf_loader.h | 11 ++++++ src/render_assets.h | 38 +++++++++++++++++++ src/vulkan_helper.cpp | 3 +- src/vulkan_helper.h | 6 ++- src/vulkan_swapchain.cpp | 2 +- src/vulkan_swapchain.h | 1 + xmake.lua | 78 +++++++++++++++++++++++++++++++++++++++ 12 files changed, 239 insertions(+), 6 deletions(-) create mode 160000 ext/glm create mode 100644 src/gltf_loader.cpp create mode 100644 src/gltf_loader.h create mode 100644 src/render_assets.h create mode 100644 xmake.lua (limited to 'src') diff --git a/.gitignore b/.gitignore index 352a5fd..41e7059 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ build/ # clangd config .clangd +.xmake # imgui config file imgui.ini diff --git a/.gitmodules b/.gitmodules index 0d0d572..ffb9b3a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "ext/stb"] path = ext/stb url = https://github.com/nothings/stb +[submodule "ext/glm"] + path = ext/glm + url = https://github.com/g-truc/glm.git diff --git a/CMakeLists.txt b/CMakeLists.txt index afe7626..ad7fd44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(argparse INTERFACE) target_include_directories(argparse INTERFACE ${EXT_DIR}/argparse/include) add_library(tinygltf INTERFACE) -target_include_directories(tinygltf INTERFACE ${EXT_DIR}/tinygltf) +target_include_directories(tinygltf INTERFACE ${EXT_DIR}/tinygltf.git) add_library(tinyobjloader INTERFACE) target_include_directories(tinyobjloader INTERFACE ${EXT_DIR}/tinyobjloader) @@ -33,6 +33,9 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_definitions(USE_VULKAN_VALIDATION_LAYERS) endif() +add_subdirectory(${EXT_DIR}/glm) +target_link_libraries(iris_renderer PRIVATE glm::glm) + find_package(glfw3 REQUIRED) target_link_libraries(iris_renderer PRIVATE glfw) diff --git a/ext/glm b/ext/glm new file mode 160000 index 0000000..33b4a62 --- /dev/null +++ b/ext/glm @@ -0,0 +1 @@ +Subproject commit 33b4a621a697a305bc3a7610d290677b96beb181 diff --git a/src/gltf_loader.cpp b/src/gltf_loader.cpp new file mode 100644 index 0000000..2b3818f --- /dev/null +++ b/src/gltf_loader.cpp @@ -0,0 +1,96 @@ +#include "gltf_loader.h" +#include "spdlog/spdlog.h" + +enum class SceneFileType { + GLTF, + GLB, + UNKNOWN, +}; + +bool load_gltf(const std::string_view path, iris::Scene &scene) { + tinygltf::Model model; + tinygltf::TinyGLTF loader; + + std::string error; + std::string warning; + + SceneFileType file_type = [&path] { + if (path.find_last_of(".") != std::string::npos) { + std::string_view extension = path.substr(path.find_last_of(".") + 1); + if (extension == "glb") { + return SceneFileType::GLB; + } else if (extension == "gltf") { + return SceneFileType::GLTF; + } + } + return SceneFileType::UNKNOWN; + }(); + switch (file_type) { + case SceneFileType::GLTF: + if (!loader.LoadASCIIFromFile(&model, &error, &warning, path.data())) { + spdlog::error("Failed to load glTF file: {}", error); + return false; + } + break; + case SceneFileType::GLB: + if (!loader.LoadBinaryFromFile(&model, &error, &warning, path.data())) { + spdlog::error("Failed to load glTF file: {}", error); + return false; + } + break; + case SceneFileType::UNKNOWN: + spdlog::error("Unknown file type: {}", path); + return false; + } + + spdlog::info("loaded glTF file {} has:\n" + "{} accessors\n" + "{} animations\n" + "{} buffers\n" + "{} bufferViews\n" + "{} materials\n" + "{} meshes\n" + "{} nodes\n" + "{} textures\n" + "{} images\n" + "{} skins\n" + "{} samplers\n" + "{} cameras\n" + "{} scenes\n" + "{} lights", + path, + model.accessors.size(), + model.animations.size(), + model.buffers.size(), + model.bufferViews.size(), + model.materials.size(), + model.meshes.size(), + model.nodes.size(), + model.textures.size(), + model.images.size(), + model.skins.size(), + model.samplers.size(), + model.cameras.size(), + model.scenes.size(), + model.lights.size()); + + for (const auto &mesh : model.meshes) { + iris::Mesh iris_mesh; + for (const auto &primitive : mesh.primitives) { + const auto &position_accessor = model.accessors[primitive.attributes.at("POSITION")]; + const auto &position_buffer_view = model.bufferViews[position_accessor.bufferView]; + const auto &position_buffer = model.buffers[position_buffer_view.buffer]; + const auto &position_data = reinterpret_cast(position_buffer.data.data() + position_buffer_view.byteOffset + position_accessor.byteOffset); + + const auto &index_accessor = model.accessors[primitive.indices]; + const auto &index_buffer_view = model.bufferViews[index_accessor.bufferView]; + const auto &index_buffer = model.buffers[index_buffer_view.buffer]; + const auto &index_data = reinterpret_cast(index_buffer.data.data() + index_buffer_view.byteOffset + index_accessor.byteOffset); + + iris_mesh.vertices.insert(iris_mesh.vertices.end(), position_data, position_data + position_accessor.count * 3); + iris_mesh.indices.insert(iris_mesh.indices.end(), index_data, index_data + index_accessor.count); + } + scene.meshes.push_back(iris_mesh); + } + return true; +} \ No newline at end of file diff --git a/src/gltf_loader.h b/src/gltf_loader.h new file mode 100644 index 0000000..c239bb2 --- /dev/null +++ b/src/gltf_loader.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include "render_assets.h" + +#define TINYGLTF_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "tiny_gltf.h" + +bool load_gltf(const std::string_view path, iris::Scene &scene); \ No newline at end of file diff --git a/src/render_assets.h b/src/render_assets.h new file mode 100644 index 0000000..763bf76 --- /dev/null +++ b/src/render_assets.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +namespace iris { + +template +struct Mesh { + std::string name; + std::vector vertices; + std::vector indices; +}; + +struct Material { + +}; + +struct Texture { +}; + +struct Camera { + glm::vec3 position; + glm::vec3 direction; + glm::vec3 up; +}; + +struct Scene { + std::vector> meshes; + std::vector materials; + std::vector textures; + + Camera camera_position; +}; + +} // namespace iris \ No newline at end of file diff --git a/src/vulkan_helper.cpp b/src/vulkan_helper.cpp index 567d414..c281b2c 100644 --- a/src/vulkan_helper.cpp +++ b/src/vulkan_helper.cpp @@ -2,7 +2,6 @@ #include "vulkan/vulkan_core.h" #include #include -#define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include #include @@ -281,7 +280,7 @@ CommandBuffer::CommandBuffer(VkDevice device, spdlog::debug("Created fence: 0x{:x}", (uint64_t)fence); } -void CommandBuffer::destroy() { +void CommandBuffer::release() { if (fence != VK_NULL_HANDLE) { vkDestroyFence(device, fence, VK_NULL_HANDLE); vkFreeCommandBuffers(device, pool, 1, &buffer); diff --git a/src/vulkan_helper.h b/src/vulkan_helper.h index 6dbf0b7..04fcead 100644 --- a/src/vulkan_helper.h +++ b/src/vulkan_helper.h @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -63,10 +65,10 @@ struct CommandBuffer { VkQueue queue; CommandBuffer(VkDevice device, uint32_t queue_family_index, VkQueue queue); - void destroy(); + void release(); void begin(VkCommandBufferUsageFlags flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); void submit_sync(); - ~CommandBuffer() { destroy(); } + ~CommandBuffer() { release(); } }; struct Device { diff --git a/src/vulkan_swapchain.cpp b/src/vulkan_swapchain.cpp index c38e9f6..4e08049 100644 --- a/src/vulkan_swapchain.cpp +++ b/src/vulkan_swapchain.cpp @@ -525,7 +525,7 @@ void Swapchain::display(Texture2D& texture) { void Swapchain::release() { upload_texture->release(); - cmd_buf.destroy(); + cmd_buf.release(); for (uint32_t i = 0; i < SWAPCHAIN_IMAGE_COUNT; i++) { vkDestroyFramebuffer(device.device, framebuffers[i], nullptr); diff --git a/src/vulkan_swapchain.h b/src/vulkan_swapchain.h index 381c5b0..8d4604e 100644 --- a/src/vulkan_swapchain.h +++ b/src/vulkan_swapchain.h @@ -1,3 +1,4 @@ +#pragma once #include "imgui_impl_glfw.h" #include "vulkan_helper.h" #include "vulkan/vulkan_core.h" diff --git a/xmake.lua b/xmake.lua new file mode 100644 index 0000000..1b9730f --- /dev/null +++ b/xmake.lua @@ -0,0 +1,78 @@ +add_rules("mode.debug", "mode.release") + +-- Project settings +set_project("iris_renderer") +set_version("1.0") +set_languages("c++20") + + +-- Project directories +local project_root = os.projectdir() +local src_dir = path.join(project_root, "src") +local ext_dir = path.join(project_root, "ext") + +-- ImGui target +target("imgui") + set_kind("static") + local imgui_dir = path.join(ext_dir, "imgui") + + -- Add source files + add_files( + path.join(imgui_dir, "imgui.cpp"), + path.join(imgui_dir, "imgui_demo.cpp"), + path.join(imgui_dir, "imgui_draw.cpp"), + path.join(imgui_dir, "imgui_tables.cpp"), + path.join(imgui_dir, "imgui_widgets.cpp"), + path.join(imgui_dir, "backends/imgui_impl_glfw.cpp"), + path.join(imgui_dir, "backends/imgui_impl_vulkan.cpp") + ) + + -- Add include directories + add_includedirs( + imgui_dir, + path.join(imgui_dir, "backends"), + {public = true} + ) + +-- Arguments for compilation +target("argparse") + set_kind("headeronly") + add_includedirs(path.join(ext_dir, "argparse/include"), {public = true}) + +target("tinygltf") + set_kind("headeronly") + add_includedirs(path.join(ext_dir, "tinygltf.git"), {public = true}) + add_cxxflags("-w") + +target("tinyobjloader") + set_kind("headeronly") + add_includedirs(path.join(ext_dir, "tinyobjloader"), {public = true}) + +target("stb") + set_kind("headeronly") + add_includedirs(path.join(ext_dir, "stb"), {public = true}) + +-- Main executable target +target("iris_renderer") + set_kind("binary") + add_files(path.join(src_dir, "**.cpp")) + + -- Link external libraries + add_deps("argparse", "imgui", "tinygltf", "tinyobjloader", "stb") + + -- Add libraries + add_packages("vulkansdk", "glfw", "fmt", "vulkan-memory-allocator", "spdlog", "glm") + add_syslinks("vulkan", "glfw", "fmt") + + -- OS-specific libraries (dl, pthread, X11, etc.) + if is_plat("linux") then + add_syslinks("dl", "pthread", "X11", "Xxf86vm", "Xrandr", "Xi") + end + + -- Compiler options + add_cxxflags("-Wall", "-Wextra", "-Wno-missing-field-initializers") + + -- Vulkan validation layers for debug builds + if is_mode("debug") then + add_defines("USE_VULKAN_VALIDATION_LAYERS") + end -- cgit v1.2.3-70-g09d2