diff --git a/CMakeLists.txt b/CMakeLists.txt
index bc81d9be2b..cc31004ebc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -623,6 +623,8 @@ add_library(Common STATIC
Common/GPU/Vulkan/VulkanRenderManager.h
Common/GPU/Vulkan/VulkanQueueRunner.cpp
Common/GPU/Vulkan/VulkanQueueRunner.h
+ Common/GPU/Vulkan/VulkanFrameData.cpp
+ Common/GPU/Vulkan/VulkanFrameData.h
Common/Input/GestureDetector.cpp
Common/Input/GestureDetector.h
Common/Input/KeyCodes.h
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index 2895cdc837..d232c01534 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -441,6 +441,7 @@
+
@@ -861,6 +862,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index ff9fd9eaa6..991b03a71f 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -419,6 +419,9 @@
GPU\Vulkan
+
+ GPU\Vulkan
+
@@ -791,6 +794,9 @@
GPU\Vulkan
+
+ GPU\Vulkan
+
diff --git a/Common/GPU/Vulkan/VulkanFrameData.cpp b/Common/GPU/Vulkan/VulkanFrameData.cpp
new file mode 100644
index 0000000000..58ce42deaf
--- /dev/null
+++ b/Common/GPU/Vulkan/VulkanFrameData.cpp
@@ -0,0 +1,15 @@
+#include "VulkanFrameData.h"
+
+void FrameData::AcquireNextImage(VulkanContext *vulkan) {
+ // Get the index of the next available swapchain image, and a semaphore to block command buffer execution on.
+ VkResult res = vkAcquireNextImageKHR(vulkan->GetDevice(), vulkan->GetSwapchain(), UINT64_MAX, acquireSemaphore, (VkFence)VK_NULL_HANDLE, &curSwapchainImage);
+ if (res == VK_SUBOPTIMAL_KHR) {
+ // Hopefully the resize will happen shortly. Ignore - one frame might look bad or something.
+ WARN_LOG(G3D, "VK_SUBOPTIMAL_KHR returned - ignoring");
+ } else if (res == VK_ERROR_OUT_OF_DATE_KHR) {
+ WARN_LOG(G3D, "VK_ERROR_OUT_OF_DATE_KHR returned - processing the frame, but not presenting");
+ skipSwap = true;
+ } else {
+ _assert_msg_(res == VK_SUCCESS, "vkAcquireNextImageKHR failed! result=%s", VulkanResultToString(res));
+ }
+}
diff --git a/Common/GPU/Vulkan/VulkanFrameData.h b/Common/GPU/Vulkan/VulkanFrameData.h
new file mode 100644
index 0000000000..21c44404b9
--- /dev/null
+++ b/Common/GPU/Vulkan/VulkanFrameData.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include
+
+#include
+#include
+
+#include "Common/GPU/Vulkan/VulkanContext.h"
+
+struct VKRStep;
+
+enum class VKRRunType {
+ END,
+ SYNC,
+};
+
+struct QueueProfileContext {
+ VkQueryPool queryPool;
+ std::vector timestampDescriptions;
+ std::string profileSummary;
+ double cpuStartTime;
+ double cpuEndTime;
+};
+
+// Per-frame data, round-robin so we can overlap submission with execution of the previous frame.
+struct FrameData {
+ std::mutex push_mutex;
+ std::condition_variable push_condVar;
+
+ std::mutex pull_mutex;
+ std::condition_variable pull_condVar;
+
+ bool readyForFence = true;
+ bool readyForRun = false;
+ bool skipSwap = false;
+ VKRRunType type = VKRRunType::END;
+
+ VkFence fence;
+ VkFence readbackFence; // Strictly speaking we might only need one of these.
+ bool readbackFenceUsed = false;
+
+ // These are on different threads so need separate pools.
+ VkCommandPool cmdPoolInit; // Written to from main thread
+ VkCommandPool cmdPoolMain; // Written to from render thread, which also submits
+
+ VkCommandBuffer initCmd;
+ VkCommandBuffer mainCmd;
+ VkCommandBuffer presentCmd;
+
+ bool hasInitCommands = false;
+ bool hasPresentCommands = false;
+
+ std::vector steps;
+
+ // Swapchain.
+ bool hasBegun = false;
+ uint32_t curSwapchainImage = -1;
+ VkSemaphore acquireSemaphore; // Not owned, shared between all FrameData.
+
+ // Profiling.
+ QueueProfileContext profile;
+ bool profilingEnabled_;
+
+ void AcquireNextImage(VulkanContext *vulkan);
+};
diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h
index fc30a0554a..d7a40000d3 100644
--- a/Common/GPU/Vulkan/VulkanQueueRunner.h
+++ b/Common/GPU/Vulkan/VulkanQueueRunner.h
@@ -8,6 +8,7 @@
#include "Common/Data/Collections/Hashmaps.h"
#include "Common/GPU/Vulkan/VulkanContext.h"
#include "Common/GPU/Vulkan/VulkanBarrier.h"
+#include "Common/GPU/Vulkan/VulkanFrameData.h"
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Data/Collections/TinySet.h"
#include "Common/GPU/DataFormat.h"
@@ -149,14 +150,6 @@ struct TransitionRequest {
VkImageLayout targetLayout;
};
-struct QueueProfileContext {
- VkQueryPool queryPool;
- std::vector timestampDescriptions;
- std::string profileSummary;
- double cpuStartTime;
- double cpuEndTime;
-};
-
class VKRRenderPass;
struct VKRStep {
diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp
index 4ce9ca1941..01180a2a44 100644
--- a/Common/GPU/Vulkan/VulkanRenderManager.cpp
+++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp
@@ -326,6 +326,8 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan
query_ci.queryCount = MAX_TIMESTAMP_QUERIES;
query_ci.queryType = VK_QUERY_TYPE_TIMESTAMP;
res = vkCreateQueryPool(vulkan_->GetDevice(), &query_ci, nullptr, &frameData_[i].profile.queryPool);
+
+ frameData_[i].acquireSemaphore = acquireSemaphore_;
}
queueRunner_.CreateDeviceObjects();
@@ -1416,23 +1418,14 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) {
SubmitInitCommands(frame);
if (!frameData.hasBegun) {
- // Get the index of the next available swapchain image, and a semaphore to block command buffer execution on.
- VkResult res = vkAcquireNextImageKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, &frameData.curSwapchainImage);
- if (res == VK_SUBOPTIMAL_KHR) {
- // Hopefully the resize will happen shortly. Ignore - one frame might look bad or something.
- WARN_LOG(G3D, "VK_SUBOPTIMAL_KHR returned - ignoring");
- } else if (res == VK_ERROR_OUT_OF_DATE_KHR) {
- WARN_LOG(G3D, "VK_ERROR_OUT_OF_DATE_KHR returned - processing the frame, but not presenting");
- frameData.skipSwap = true;
- } else {
- _assert_msg_(res == VK_SUCCESS, "vkAcquireNextImageKHR failed! result=%s", VulkanResultToString(res));
- }
+ frameData.AcquireNextImage(vulkan_);
+ // Effectively resets both main and present command buffers, since they both live in this pool.
vkResetCommandPool(vulkan_->GetDevice(), frameData.cmdPoolMain, 0);
+
VkCommandBufferBeginInfo begin{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- res = vkBeginCommandBuffer(frameData.mainCmd, &begin);
-
+ VkResult res = vkBeginCommandBuffer(frameData.mainCmd, &begin);
_assert_msg_(res == VK_SUCCESS, "vkBeginCommandBuffer failed! result=%s", VulkanResultToString(res));
queueRunner_.SetBackbuffer(framebuffers_[frameData.curSwapchainImage], swapchainImages_[frameData.curSwapchainImage].image);
diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h
index 362e94bcac..e34c1a6550 100644
--- a/Common/GPU/Vulkan/VulkanRenderManager.h
+++ b/Common/GPU/Vulkan/VulkanRenderManager.h
@@ -65,11 +65,6 @@ private:
std::string tag_;
};
-enum class VKRRunType {
- END,
- SYNC,
-};
-
enum {
MAX_TIMESTAMP_QUERIES = 128,
};
@@ -487,45 +482,6 @@ private:
VkSemaphore acquireSemaphore_;
VkSemaphore renderingCompleteSemaphore_;
- // Per-frame data, round-robin so we can overlap submission with execution of the previous frame.
- struct FrameData {
- std::mutex push_mutex;
- std::condition_variable push_condVar;
-
- std::mutex pull_mutex;
- std::condition_variable pull_condVar;
-
- bool readyForFence = true;
- bool readyForRun = false;
- bool skipSwap = false;
- VKRRunType type = VKRRunType::END;
-
- VkFence fence;
- VkFence readbackFence; // Strictly speaking we might only need one of these.
- bool readbackFenceUsed = false;
-
- // These are on different threads so need separate pools.
- VkCommandPool cmdPoolInit; // Written to from main thread
- VkCommandPool cmdPoolMain; // Written to from render thread, which also submits
-
- VkCommandBuffer initCmd;
- VkCommandBuffer mainCmd;
- VkCommandBuffer presentCmd;
-
- bool hasInitCommands = false;
- bool hasPresentCommands = false;
-
- std::vector steps;
-
- // Swapchain.
- bool hasBegun = false;
- uint32_t curSwapchainImage = -1;
-
- // Profiling.
- QueueProfileContext profile;
- bool profilingEnabled_;
- };
-
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
int newInflightFrames_ = -1;
int inflightFramesAtStart_ = 0;
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index b47db9d5cc..f317315e0a 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -51,6 +51,7 @@ VULKAN_FILES := \
$(SRC)/Common/GPU/Vulkan/thin3d_vulkan.cpp \
$(SRC)/Common/GPU/Vulkan/VulkanQueueRunner.cpp \
$(SRC)/Common/GPU/Vulkan/VulkanRenderManager.cpp \
+ $(SRC)/Common/GPU/Vulkan/VulkanFrameData.cpp \
$(SRC)/Common/GPU/Vulkan/VulkanLoader.cpp \
$(SRC)/Common/GPU/Vulkan/VulkanContext.cpp \
$(SRC)/Common/GPU/Vulkan/VulkanDebug.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index ab2c4bfe1c..f08bd45633 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -253,6 +253,7 @@ SOURCES_CXX += \
$(COMMONDIR)/GPU/Vulkan/thin3d_vulkan.cpp \
$(COMMONDIR)/GPU/Vulkan/VulkanQueueRunner.cpp \
$(COMMONDIR)/GPU/Vulkan/VulkanRenderManager.cpp \
+ $(COMMONDIR)/GPU/Vulkan/VulkanFrameData.cpp \
$(COMMONDIR)/GPU/Vulkan/VulkanLoader.cpp \
$(COMMONDIR)/GPU/Vulkan/VulkanContext.cpp \
$(COMMONDIR)/GPU/Vulkan/VulkanDebug.cpp \