#pragma once #include #include #include #include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/Data/Collections/Hashmaps.h" enum { MAX_TIMESTAMP_QUERIES = 128, }; enum class VKRRunType { SUBMIT, PRESENT, SYNC, EXIT, }; struct QueueProfileContext { bool enabled = false; bool timestampsEnabled = false; VkQueryPool queryPool; std::vector timestampDescriptions; std::string profileSummary; double cpuStartTime; double cpuEndTime; double descWriteTime; }; class VKRFramebuffer; struct ReadbackKey { const VKRFramebuffer *framebuf; int width; int height; }; struct CachedReadback { VkBuffer buffer; VmaAllocation allocation; VkDeviceSize bufferSize; bool isCoherent; void Destroy(VulkanContext *vulkan); }; struct FrameDataShared { // Permanent objects VkSemaphore acquireSemaphore = VK_NULL_HANDLE; VkSemaphore renderingCompleteSemaphore = VK_NULL_HANDLE; // For synchronous readbacks. VkFence readbackFence = VK_NULL_HANDLE; bool useMultiThreading; bool measurePresentTime; void Init(VulkanContext *vulkan, bool useMultiThreading, bool measurePresentTime); void Destroy(VulkanContext *vulkan); }; enum class FrameSubmitType { Pending, Sync, Present, }; // Per-frame data, round-robin so we can overlap submission with execution of the previous frame. struct FrameData { bool skipSwap = false; std::mutex fenceMutex; std::condition_variable fenceCondVar; bool readyForFence = true; VkFence fence = VK_NULL_HANDLE; // These are on different threads so need separate pools. VkCommandPool cmdPoolInit = VK_NULL_HANDLE; // Written to from main thread VkCommandPool cmdPoolMain = VK_NULL_HANDLE; // Written to from render thread, which also submits VkCommandBuffer initCmd = VK_NULL_HANDLE; VkCommandBuffer mainCmd = VK_NULL_HANDLE; VkCommandBuffer presentCmd = VK_NULL_HANDLE; bool hasInitCommands = false; bool hasMainCommands = false; bool hasPresentCommands = false; bool hasFencePending = false; bool hasAcquired = false; bool syncDone = false; // Swapchain. uint32_t curSwapchainImage = -1; // Frames need unique IDs to wait for present on, let's keep them here. // Also used for indexing into the frame timing history buffer. uint64_t frameId = 0; // Profiling. QueueProfileContext profile{}; // Async readback cache. DenseHashMap readbacks_; FrameData() : readbacks_(8) {} void Init(VulkanContext *vulkan, int index); void Destroy(VulkanContext *vulkan); void AcquireNextImage(VulkanContext *vulkan, FrameDataShared &shared); VkResult QueuePresent(VulkanContext *vulkan, FrameDataShared &shared); // Generally called from the main thread, unlike most of the rest. VkCommandBuffer GetInitCmd(VulkanContext *vulkan); // This will only submit if we are actually recording init commands. void SubmitPending(VulkanContext *vulkan, FrameSubmitType type, FrameDataShared &shared); private: // Metadata for logging etc int index = -1; };