// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.h // Copyright (c) 2025-2026 MobileGL-Dev // Licensed under the GNU Lesser General Public License v3.0: // https://www.gnu.org/licenses/gpl-3.0.txt // https://www.gnu.org/licenses/lgpl-3.0.txt // SPDX-License-Identifier: LGPL-3.0-only // End of Source File Header #pragma once #include "../VkIncludes.h" #include namespace MobileGL::MG_Backend::DirectVulkan { class FrameContext { public: struct SubmitInfoPacket { VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; VkSemaphore waitSemaphore = VK_NULL_HANDLE; VkSemaphore signalSemaphore = VK_NULL_HANDLE; VkCommandBuffer commandBuffer = VK_NULL_HANDLE; VkSubmitInfo submitInfo{VK_STRUCTURE_TYPE_SUBMIT_INFO}; }; struct PresentInfoPacket { VkSemaphore waitSemaphore = VK_NULL_HANDLE; VkSwapchainKHR swapchain = VK_NULL_HANDLE; const Uint32* imageIndex = nullptr; VkPresentInfoKHR presentInfo{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; }; struct FrameData { VkCommandBuffer commandBuffer = VK_NULL_HANDLE; VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE; VkFence imageInFlightFence = VK_NULL_HANDLE; Bool isCommandRecording = false; Bool hasCommandBufferRecorded = false; }; VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount); void Destroy(VkDevice device, VkCommandPool commandPool); // Lifecycle functions FrameData& GetCurrent(); const FrameData& GetCurrent() const; Bool IsCommandRecording() const; void AdvanceToNext(); VkCommandBuffer& BeginCommandRecording(VkCommandBufferUsageFlags flags = 0, const VkCommandBufferInheritanceInfo* pInheritanceInfo = nullptr); void EndCommandRecording(); VkResult InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount); void DestroySwapchainSemaphores(VkDevice device); Bool TransitionToPresent(VkImage image, VkImageLayout oldLayout, VkImageLayout presentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer, Uint32 swapchainImageIndex) const; PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const; VkResult WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex, Uint64 timeout = UINT64_MAX, VkFence acquireFence = VK_NULL_HANDLE); Uint32 GetCurrentFrameIndex() const; Uint32 GetFrameCount() const; private: void AssertValidFrameIndex(Uint32 frameIndex) const; void AssertValidSwapchainImageIndex(Uint32 imageIndex) const; VkResult CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex, const VkSemaphoreCreateInfo& semaphoreInfo, const VkFenceCreateInfo& fenceInfo); void DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex); Vector m_frames; Vector m_swapchainImageRenderFinishedSemaphores; Uint32 currentFrameIndex = 0; }; } // namespace MobileGL::MG_Backend::DirectVulkan