From 03c746d8a6c26915b11af1a24ad3ebd94d453800 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Fri, 14 Jun 2024 18:38:48 +0200 Subject: Command buffer submission --- .clang-tidy | 1 + deimos/core/allocator.h | 13 +++ deimos/vulkan/vulkan_backend.cpp | 149 ++++++++++++++++++++++++++++-- deimos/vulkan/vulkan_device_functions.inc | 5 + 4 files changed, 159 insertions(+), 9 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 3cedbdc..1abd5fd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -27,3 +27,4 @@ Checks: - "-*-bounds-array-to-pointer-decay" - "-*-no-array-decay" - "-*-signed-bitwise" + - "-readability-use-anyofallof" diff --git a/deimos/core/allocator.h b/deimos/core/allocator.h index f6adea2..569b0df 100644 --- a/deimos/core/allocator.h +++ b/deimos/core/allocator.h @@ -188,6 +188,19 @@ public: } return Span{ (T*)raw, count }; } + + template + void DeleteArray(gsl::owner> arr, const SourceLocation& source_location = {}) + { + if constexpr (!std::is_trivially_destructible_v) + { + for (T* p = arr.data(), end = arr.end(); p < end; ++p) + { + p->~T(); + } + } + Free(arr.data(), arr.size_bytes(), source_location); + } }; class AllocatorApi diff --git a/deimos/vulkan/vulkan_backend.cpp b/deimos/vulkan/vulkan_backend.cpp index cc54d4d..4334111 100644 --- a/deimos/vulkan/vulkan_backend.cpp +++ b/deimos/vulkan/vulkan_backend.cpp @@ -9,10 +9,66 @@ #include #include -namespace +using namespace deimos; + +void DeimosFormat(IWriter* writer, VkResult res) { +#define PRINT_RESULT(X) case VK_##X: writer->Write(AsBytes(StringView(#X))); break; + switch (res) + { + PRINT_RESULT(SUCCESS); + PRINT_RESULT(NOT_READY); + PRINT_RESULT(TIMEOUT); + PRINT_RESULT(EVENT_SET); + PRINT_RESULT(EVENT_RESET); + PRINT_RESULT(INCOMPLETE); + PRINT_RESULT(ERROR_OUT_OF_HOST_MEMORY); + PRINT_RESULT(ERROR_OUT_OF_DEVICE_MEMORY); + PRINT_RESULT(ERROR_INITIALIZATION_FAILED); + PRINT_RESULT(ERROR_DEVICE_LOST); + PRINT_RESULT(ERROR_MEMORY_MAP_FAILED); + PRINT_RESULT(ERROR_LAYER_NOT_PRESENT); + PRINT_RESULT(ERROR_EXTENSION_NOT_PRESENT); + PRINT_RESULT(ERROR_FEATURE_NOT_PRESENT); + PRINT_RESULT(ERROR_INCOMPATIBLE_DRIVER); + PRINT_RESULT(ERROR_TOO_MANY_OBJECTS); + PRINT_RESULT(ERROR_FORMAT_NOT_SUPPORTED); + PRINT_RESULT(ERROR_FRAGMENTED_POOL); + PRINT_RESULT(ERROR_UNKNOWN); + PRINT_RESULT(ERROR_OUT_OF_POOL_MEMORY); + PRINT_RESULT(ERROR_INVALID_EXTERNAL_HANDLE); + PRINT_RESULT(ERROR_FRAGMENTATION); + PRINT_RESULT(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS); + PRINT_RESULT(PIPELINE_COMPILE_REQUIRED); + PRINT_RESULT(ERROR_SURFACE_LOST_KHR); + PRINT_RESULT(ERROR_NATIVE_WINDOW_IN_USE_KHR); + PRINT_RESULT(SUBOPTIMAL_KHR); + PRINT_RESULT(ERROR_OUT_OF_DATE_KHR); + PRINT_RESULT(ERROR_INCOMPATIBLE_DISPLAY_KHR); + PRINT_RESULT(ERROR_VALIDATION_FAILED_EXT); + PRINT_RESULT(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR); + PRINT_RESULT(ERROR_NOT_PERMITTED_KHR); + PRINT_RESULT(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT); + PRINT_RESULT(THREAD_IDLE_KHR); + PRINT_RESULT(THREAD_DONE_KHR); + PRINT_RESULT(OPERATION_DEFERRED_KHR); + PRINT_RESULT(OPERATION_NOT_DEFERRED_KHR); + PRINT_RESULT(ERROR_INCOMPATIBLE_SHADER_BINARY_EXT); + PRINT_RESULT(ERROR_INVALID_SHADER_NV); + PRINT_RESULT(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR); + PRINT_RESULT(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR); + PRINT_RESULT(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR); + PRINT_RESULT(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR); + PRINT_RESULT(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR); + PRINT_RESULT(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT); + PRINT_RESULT(ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR); + PRINT_RESULT(ERROR_COMPRESSION_EXHAUSTED_EXT); + PRINT_RESULT(RESULT_MAX_ENUM); + } +} -using namespace deimos; +namespace +{ LogApi* log_api; OsApi* os_api; @@ -24,7 +80,9 @@ const VkAllocationCallbacks* kVkAlloc = nullptr; struct VulkanSwapchain: public RenderSwapchain { - VkSwapchainKHR swapchain{}; + VkSwapchainKHR swapchain{}; + VkFormat format{}; + gsl::owner> images; }; class VulkanBackendImpl : public IVulkanBackend, public IRenderBackend @@ -40,7 +98,8 @@ class VulkanBackendImpl : public IVulkanBackend, public IRenderBackend struct FrameResources { - VkCommandPool cmd_pool = VK_NULL_HANDLE; + VkCommandPool cmd_pool = VK_NULL_HANDLE; + VkCommandBuffer cmd_buffer = VK_NULL_HANDLE; }; FrameResources m_frame_resources; @@ -78,13 +137,65 @@ public: VkResult res = m_vk->CreateCommandPool(m_device, &create_info, kVkAlloc, &m_frame_resources.cmd_pool); if (res != VK_SUCCESS) { - log_api->LogError("Couldn't allocate Vulkan command pool: $", (int)res); + log_api->LogError("Couldn't allocate Vulkan command pool: $", res); return; } + + VkCommandBufferAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + alloc_info.pNext = nullptr; + alloc_info.commandPool = m_frame_resources.cmd_pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + + res = m_vk->AllocateCommandBuffers(m_device, &alloc_info, &m_frame_resources.cmd_buffer); + if (res != VK_SUCCESS) + { + log_api->LogError("Couldn't allocate Vulkan command buffer: $", res); + } + + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.pNext = nullptr; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + begin_info.pInheritanceInfo = nullptr; + + res = m_vk->BeginCommandBuffer(m_frame_resources.cmd_buffer, &begin_info); + if (res != VK_SUCCESS) + { + log_api->LogError("Couldn't begin Vulkan command buffer recording: $", res); + } } void EndFrame() override { + VkResult res = m_vk->EndCommandBuffer(m_frame_resources.cmd_buffer); + if (res != VK_SUCCESS) + { + log_api->LogError("Couldn't end Vulkan command buffer recording: $", res); + } + + VkCommandBufferSubmitInfo cmd_buffer_submit_info{}; + cmd_buffer_submit_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + cmd_buffer_submit_info.pNext = nullptr; + cmd_buffer_submit_info.commandBuffer = m_frame_resources.cmd_buffer; + cmd_buffer_submit_info.deviceMask = 0; + + VkSubmitInfo2 submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2; + submit_info.pNext = nullptr; + submit_info.flags = 0; + submit_info.waitSemaphoreInfoCount = 0; + submit_info.commandBufferInfoCount = 1; + submit_info.pCommandBufferInfos = &cmd_buffer_submit_info; + submit_info.signalSemaphoreInfoCount = 0; + + res = m_vk->QueueSubmit2(m_queue, 1, &submit_info, VK_NULL_HANDLE); + if (res != VK_SUCCESS) + { + log_api->LogError("Couldn't submit Vulkan queue: $", res); + } + m_vk->DeviceWaitIdle(m_device); m_vk->DestroyCommandPool(m_device, m_frame_resources.cmd_pool, kVkAlloc); } @@ -148,7 +259,7 @@ public: return RuntimeError("No acceptable Vulkan swapchain format found"); } - VkSwapchainCreateInfoKHR create_info = { + const VkSwapchainCreateInfoKHR create_info = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = nullptr, .flags = 0, @@ -177,15 +288,29 @@ public: } auto* swapchain = m_allocator->New(); - swapchain->swapchain = vk_swapchain; + swapchain->swapchain = vk_swapchain; + swapchain->format = format.format; + + uint32_t image_count = 0; + res = m_vk->GetSwapchainImagesKHR(m_device, vk_swapchain, &image_count, nullptr); + if (res != VK_SUCCESS) + { + return RuntimeError("Error when retrieving Vulkan swapchain images"); + } + + swapchain->images = m_allocator->NewArray(image_count); + m_vk->GetSwapchainImagesKHR(m_device, vk_swapchain, &image_count, swapchain->images.data()); + + log_api->LogInfo("Vulkan swapchain created with $ images, format $, present mode $", image_count, (int)format.format, (int)present_mode); return swapchain; } void DestroySwapchain(gsl::owner swapchain) override { - auto* vk_swapchain = (VulkanSwapchain*)swapchain; + auto* vk_swapchain = (VulkanSwapchain*)swapchain; // NOLINT m_vk->DestroySwapchainKHR(m_device, vk_swapchain->swapchain, kVkAlloc); + m_allocator->DeleteArray(vk_swapchain->images); m_allocator->Delete(swapchain); } }; @@ -358,10 +483,16 @@ StatusOr CreateDevice(VulkanApi* vk, VkPhysicalDevice physical_device, const char* extensions[]{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; + + const VkPhysicalDeviceSynchronization2Features synchronization2_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, + .pNext = nullptr, + .synchronization2 = VK_TRUE, + }; const VkDeviceCreateInfo create_info{ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = nullptr, + .pNext = &synchronization2_features, .flags = 0, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_create_info, diff --git a/deimos/vulkan/vulkan_device_functions.inc b/deimos/vulkan/vulkan_device_functions.inc index f6e6a30..6aa30d2 100644 --- a/deimos/vulkan/vulkan_device_functions.inc +++ b/deimos/vulkan/vulkan_device_functions.inc @@ -6,6 +6,11 @@ FN(GetDeviceQueue) FN(CreateCommandPool) FN(ResetCommandPool) FN(DestroyCommandPool) +FN(AllocateCommandBuffers) +FN(FreeCommandBuffers) +FN(BeginCommandBuffer) +FN(EndCommandBuffer) +FN(QueueSubmit2) FN(CreateSwapchainKHR) FN(DestroySwapchainKHR) -- cgit