diff --git a/CMakeLists.txt b/CMakeLists.txt
index cc31004ebc..7af3e586d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -659,6 +659,8 @@ add_library(Common STATIC
Common/Net/WebsocketServer.h
Common/Profiler/Profiler.cpp
Common/Profiler/Profiler.h
+ Common/Profiler/EventStream.cpp
+ Common/Profiler/EventStream.h
Common/Render/TextureAtlas.cpp
Common/Render/TextureAtlas.h
Common/Render/DrawBuffer.cpp
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index d232c01534..fe2c405c1a 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -466,6 +466,7 @@
+
@@ -886,6 +887,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index 991b03a71f..6cf34049df 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -422,6 +422,9 @@
GPU\Vulkan
+
+ Profiler
+
@@ -797,6 +800,9 @@
GPU\Vulkan
+
+ Profiler
+
diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp
index b52e4396cb..83b3d974c0 100644
--- a/Common/GPU/Vulkan/VulkanDebug.cpp
+++ b/Common/GPU/Vulkan/VulkanDebug.cpp
@@ -93,4 +93,3 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
// keep that behavior here.
return false;
}
-
diff --git a/Common/GPU/Vulkan/VulkanFrameData.h b/Common/GPU/Vulkan/VulkanFrameData.h
index 9fdd865ebf..6a0f4316d8 100644
--- a/Common/GPU/Vulkan/VulkanFrameData.h
+++ b/Common/GPU/Vulkan/VulkanFrameData.h
@@ -6,6 +6,7 @@
#include
#include "Common/GPU/Vulkan/VulkanContext.h"
+#include "Common/Profiler/EventStream.h"
enum {
MAX_TIMESTAMP_QUERIES = 128,
@@ -74,6 +75,8 @@ struct FrameData {
// Profiling.
QueueProfileContext profile;
bool profilingEnabled_;
+ EventStream *mainThreadEvents;
+ EventStream *renderThreadEvents;
void Init(VulkanContext *vulkan, int index);
void Destroy(VulkanContext *vulkan);
diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp
index 542ba7a1e2..f1adde1858 100644
--- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp
+++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp
@@ -6,6 +6,8 @@
#include "Common/Log.h"
#include "Common/TimeUtil.h"
+#include "Common/Profiler/EventStream.h"
+
using namespace PPSSPP_VK;
// Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP NativeGLView NativeRenderer NativeSurfaceView PowerSaveModeReceiver InputDeviceState
@@ -555,6 +557,8 @@ void VulkanQueueRunner::PreprocessSteps(std::vector &steps) {
}
void VulkanQueueRunner::RunSteps(std::vector &steps, FrameData &frameData, FrameDataShared &frameDataShared) {
+ EventScope scope(frameData.renderThreadEvents, "run_steps", EventStream::EventType::COMPUTE);
+
QueueProfileContext *profile = frameData.profilingEnabled_ ? &frameData.profile : nullptr;
if (profile)
diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp
index a666a830de..7ba9e6f113 100644
--- a/Common/GPU/Vulkan/VulkanRenderManager.cpp
+++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp
@@ -13,6 +13,8 @@
#include "Common/Thread/ThreadUtil.h"
+#include "Common/Profiler/EventStream.h"
+
#if 0 // def _DEBUG
#define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__)
#else
@@ -292,12 +294,18 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int
}
VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan), queueRunner_(vulkan) {
+ mainThreadEvents_ = g_eventStreamManager.Get("render_main");
+ renderThreadEvents_ = g_eventStreamManager.Get("render_submit");
+
inflightFramesAtStart_ = vulkan_->GetInflightFrames();
frameDataShared_.Init(vulkan);
for (int i = 0; i < inflightFramesAtStart_; i++) {
frameData_[i].Init(vulkan, i);
+
+ frameData_[i].mainThreadEvents = mainThreadEvents_;
+ frameData_[i].renderThreadEvents = renderThreadEvents_;
}
queueRunner_.CreateDeviceObjects();
@@ -472,6 +480,7 @@ void VulkanRenderManager::ThreadFunc() {
// Pop a task of the queue and execute it.
VKRRenderThreadTask task;
{
+ EventScope scope(renderThreadEvents_, "idle", EventStream::EventType::BLOCK);
std::unique_lock lock(pushMutex_);
while (renderThreadQueue_.empty()) {
pushCondVar_.wait(lock);
@@ -480,6 +489,7 @@ void VulkanRenderManager::ThreadFunc() {
renderThreadQueue_.pop();
}
+ renderThreadEvents_->SetFrameId(task.frame);
// Oh, we got a task! We can now have pushMutex_ unlocked, allowing the host to
// push more work when it feels like it, and just start working.
if (task.runType == VKRRunType::EXIT) {
@@ -504,24 +514,29 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling, bool enableLogProfile
int curFrame = vulkan_->GetCurFrame();
FrameData &frameData = frameData_[curFrame];
+ mainThreadEvents_->SetFrameId(curFrame);
+
VLOG("PUSH: Fencing %d", curFrame);
// Makes sure the submission from the previous time around has happened. Otherwise
// we are not allowed to wait from another thread here..
{
- std::unique_lock lock(frameData.fenceMutex);
- while (!frameData.readyForFence) {
- frameData.fenceCondVar.wait(lock);
+ EventScope scope(mainThreadEvents_, "fence", EventStream::EventType::BLOCK);
+ {
+ std::unique_lock lock(frameData.fenceMutex);
+ while (!frameData.readyForFence) {
+ frameData.fenceCondVar.wait(lock);
+ }
+ frameData.readyForFence = false;
}
- frameData.readyForFence = false;
- }
- // This must be the very first Vulkan call we do in a new frame.
- // Makes sure the very last command buffer from the frame before the previous has been fully executed.
- if (vkWaitForFences(device, 1, &frameData.fence, true, UINT64_MAX) == VK_ERROR_DEVICE_LOST) {
- _assert_msg_(false, "Device lost in vkWaitForFences");
+ // This must be the very first Vulkan call we do in a new frame.
+ // Makes sure the very last command buffer from the frame before the previous has been fully executed.
+ if (vkWaitForFences(device, 1, &frameData.fence, true, UINT64_MAX) == VK_ERROR_DEVICE_LOST) {
+ _assert_msg_(false, "Device lost in vkWaitForFences");
+ }
+ vkResetFences(device, 1, &frameData.fence);
}
- vkResetFences(device, 1, &frameData.fence);
// Can't set this until after the fence.
frameData.profilingEnabled_ = enableProfiling;
@@ -1172,6 +1187,7 @@ void VulkanRenderManager::Finish() {
FrameData &frameData = frameData_[curFrame];
{
+ EventScope scope(mainThreadEvents_, "push", EventStream::EventType::COMPUTE);
VLOG("PUSH: Frame[%d]", curFrame);
VKRRenderThreadTask task;
task.frame = curFrame;
diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h
index ed9f0d16e5..9d4e7e0c7d 100644
--- a/Common/GPU/Vulkan/VulkanRenderManager.h
+++ b/Common/GPU/Vulkan/VulkanRenderManager.h
@@ -529,4 +529,7 @@ private:
// pipelines to check and possibly create at the end of the current render pass.
std::vector pipelinesToCheck_;
+
+ EventStream *mainThreadEvents_;
+ EventStream *renderThreadEvents_;
};
diff --git a/Common/Input/InputState.h b/Common/Input/InputState.h
index faa6416e30..c5ed420c5c 100644
--- a/Common/Input/InputState.h
+++ b/Common/Input/InputState.h
@@ -98,6 +98,7 @@ public:
}
};
+// Used for both touch and mouse.
enum {
TOUCH_MOVE = 1 << 0,
TOUCH_DOWN = 1 << 1,
@@ -106,6 +107,7 @@ enum {
TOUCH_WHEEL = 1 << 4, // Scrollwheel event. Usually only affects Y but can potentially affect X.
TOUCH_MOUSE = 1 << 5, // Identifies that this touch event came from a mouse
TOUCH_RELEASE_ALL = 1 << 6, // Useful for app focus switches when events may be lost.
+ TOUCH_HOVER_MOVE = 1 << 7, // Same as move but also happens when no button is pressed. Only works for mice, of course.
// These are the Android getToolType() codes, shifted by 10.
TOUCH_TOOL_MASK = 7 << 10,
diff --git a/Common/Profiler/EventStream.cpp b/Common/Profiler/EventStream.cpp
new file mode 100644
index 0000000000..f7009ee732
--- /dev/null
+++ b/Common/Profiler/EventStream.cpp
@@ -0,0 +1,114 @@
+#include