diff --git a/include/Orange/Render/RenderContext.h b/include/Orange/Render/RenderContext.h index 67e243d..9544740 100644 --- a/include/Orange/Render/RenderContext.h +++ b/include/Orange/Render/RenderContext.h @@ -22,6 +22,10 @@ namespace orange VkPhysicalDevice PhysicalDevice() const { return m_physicalDevice; } VkDevice Device() const { return m_device; } VkQueue Queue() const { return m_queue; } + VkCommandPool CommandPool() const { return m_commandPool; } + + VulkanResult CreateFence(bool signalled); + VulkanResult CreateSemaphore(); protected: friend VulkanResult; RenderContext(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device, diff --git a/include/Orange/Render/Swapchain.h b/include/Orange/Render/Swapchain.h index 720311f..2951d09 100644 --- a/include/Orange/Render/Swapchain.h +++ b/include/Orange/Render/Swapchain.h @@ -5,35 +5,56 @@ #include #include +#include namespace orange { + static constexpr uint32_t MaxFramesInFlight = 4; + class Swapchain { public: ~Swapchain(); static Result Create(RenderContext& context, VkSurfaceKHR surface); + + VkCommandBuffer CommandBuffer() const { return m_commandBuffers[m_currentImage]; } protected: friend class Result; - Swapchain(VkDevice device, VkSurfaceKHR surface, VkFormat format, VkExtent2D extent, VkSwapchainKHR swapchain, - Span images, Span imageViews) - : m_device { device } - , m_surface { surface } - , m_format { format } - , m_extent { extent } - , m_swapchain { swapchain } - , m_images { images } - , m_imageViews{ imageViews } + Swapchain(RenderContext& context, VkSurfaceKHR surface, VkFormat format, VkExtent2D extent, VkSwapchainKHR swapchain, + Span images, Span imageViews, Span commandBuffers, + Span imageAvailableSemaphores, Span renderFinishedSemaphores, Span inFlightFences, + uint32_t currentImage) + : m_ctx { context } + , m_surface { surface } + , m_format { format } + , m_extent { extent } + , m_swapchain { swapchain } + , m_images { images } + , m_imageViews { imageViews } + , m_commandBuffers { commandBuffers } + , m_imageAvailableSemaphores { imageAvailableSemaphores } + , m_renderFinishedSemaphores { renderFinishedSemaphores } + , m_inFlightFences { inFlightFences } + , m_currentImage { currentImage } {} + private: - VkDevice m_device; + RenderContext& m_ctx; VkSurfaceKHR m_surface; VkFormat m_format; VkExtent2D m_extent; VkSwapchainKHR m_swapchain; - SmallVector m_images; - SmallVector m_imageViews; + SmallVector m_images; + SmallVector m_imageViews; + + SmallVector m_commandBuffers; + SmallVector m_imageAvailableSemaphores; + SmallVector m_renderFinishedSemaphores; + SmallVector m_inFlightFences; + + uint32_t m_currentFrame = 0; + uint32_t m_currentImage = 0; }; } \ No newline at end of file diff --git a/src/Orange/Render/RenderContext_Init.cpp b/src/Orange/Render/RenderContext_Init.cpp index c0291f8..6873583 100644 --- a/src/Orange/Render/RenderContext_Init.cpp +++ b/src/Orange/Render/RenderContext_Init.cpp @@ -182,6 +182,7 @@ namespace orange RenderContext::~RenderContext() { + vkDestroyCommandPool(m_device, m_commandPool, nullptr); vkDestroyDevice(m_device, nullptr); vkDestroyInstance(m_instance, nullptr); } diff --git a/src/Orange/Render/RenderContext_Util.cpp b/src/Orange/Render/RenderContext_Util.cpp new file mode 100644 index 0000000..75d11ca --- /dev/null +++ b/src/Orange/Render/RenderContext_Util.cpp @@ -0,0 +1,36 @@ +#include +#include + +namespace orange +{ + VulkanResult RenderContext::CreateFence(bool signalled) + { + VkFenceCreateInfo fenceInfo = + { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = signalled ? VK_FENCE_CREATE_SIGNALED_BIT : 0u, + }; + + VkFence fence = VK_NULL_HANDLE; + VkResult res = VK_SUCCESS; + if ((res = vkCreateFence(m_device, &fenceInfo, nullptr, &fence)) != VK_SUCCESS) + return VulkanResult::Error(res); + + return VulkanResult::Success(fence); + } + + VulkanResult RenderContext::CreateSemaphore() + { + VkSemaphoreCreateInfo semaphoreInfo = + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }; + + VkSemaphore semaphore = VK_NULL_HANDLE; + VkResult res = VK_SUCCESS; + if ((res = vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &semaphore)) != VK_SUCCESS) + return VulkanResult::Error(res); + + return VulkanResult::Success(semaphore); + } +} diff --git a/src/Orange/Render/Swapchain.cpp b/src/Orange/Render/Swapchain.cpp index eea4f7e..ab56de5 100644 --- a/src/Orange/Render/Swapchain.cpp +++ b/src/Orange/Render/Swapchain.cpp @@ -3,9 +3,12 @@ #include #include #include +#include namespace orange { + static constexpr uint32_t DefaultFramesInFlight = 2; + static Result ChooseSwapChainFormat(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { SmallVector surfaceFormats; @@ -96,11 +99,11 @@ namespace orange if (vkCreateSwapchainKHR(context.Device(), &swapchainInfo, nullptr, &swapchain) != VK_SUCCESS) return Result::PrintError("Failed to create swapchain"); - SmallVector swapchainImages; + SmallVector swapchainImages; if (!VkEnumerate(vkGetSwapchainImagesKHR, swapchainImages, context.Device(), swapchain)) return Result::PrintError("Failed to get swapchain images"); - SmallVector swapchainImageViews{ swapchainImages.Size() }; + SmallVector swapchainImageViews{ swapchainImages.Size() }; for (size_t i = 0; i < swapchainImages.Size(); i++) { VkImageViewCreateInfo imageViewInfo = @@ -116,15 +119,47 @@ namespace orange return Result::PrintError("Failed to get swapchain image view"); } - return Result::Success( - context.Device(), surface, r_format->format, extent, swapchain, - swapchainImages, swapchainImageViews); + SmallVector commandBuffers{ DefaultFramesInFlight }; + { + VkCommandBufferAllocateInfo commandBufferInfo = + { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = context.CommandPool(), + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = DefaultFramesInFlight, + }; + + if (vkAllocateCommandBuffers(context.Device(), &commandBufferInfo, commandBuffers.Data()) != VK_SUCCESS) + return Result::PrintError("Failed to get swapchain image view"); + } + + SmallVector imageAvailableSemaphores{ DefaultFramesInFlight }; + SmallVector renderFinishedSemaphores{ DefaultFramesInFlight }; + SmallVector inFlightFences { DefaultFramesInFlight }; + for (uint32_t i = 0; i < DefaultFramesInFlight; i++) + { + auto r_fence = context.CreateFence(true); + if (!r_fence) return Result::PrintError("Failed to create fence for swapchain"); + inFlightFences[i] = *r_fence; + + auto r_imageSem = context.CreateSemaphore(); + if (!r_imageSem) return Result::PrintError("Failed to create semaphore for swapchain"); + imageAvailableSemaphores[i] = *r_imageSem; + + auto r_renderSem = context.CreateSemaphore(); + if (!r_renderSem) return Result::PrintError("Failed to create semaphore for swapchain"); + renderFinishedSemaphores[i] = *r_renderSem; + } + + // TODO: Handle failure + uint32_t imageIndex; + vkAcquireNextImageKHR(context.Device(), swapchain, ~0u, imageAvailableSemaphores[0], VK_NULL_HANDLE, &imageIndex); } Swapchain::~Swapchain() { for (const auto& imageView : m_imageViews) - vkDestroyImageView(m_device, imageView, nullptr); - vkDestroySwapchainKHR(m_device, m_swapchain, nullptr); + vkDestroyImageView(m_ctx.Device(), imageView, nullptr); + vkDestroySwapchainKHR(m_ctx.Device(), m_swapchain, nullptr); } } \ No newline at end of file diff --git a/src/Orange/meson.build b/src/Orange/meson.build index a0e5cfd..b930bec 100644 --- a/src/Orange/meson.build +++ b/src/Orange/meson.build @@ -2,6 +2,7 @@ orange_src = [ 'Core/Log.cpp', 'Render/RenderContext_Init.cpp', + 'Render/RenderContext_Util.cpp', 'Render/Swapchain.cpp', 'Render/Window.cpp', ]