From 328d89db708ec9c1d3e31a760f530b64c4767b2b Mon Sep 17 00:00:00 2001
From: Stenzek <stenzek@gmail.com>
Date: Wed, 2 Oct 2019 21:32:44 +1000
Subject: [PATCH] Vulkan: Add a DriverDetails bug for "slow cached readback
 memory"

Using the cached memory type appears to be slower on Mali drivers, with
~10-15% CPU spent in the __pi___inval_cache_range kernel function.
---
 Source/Core/VideoBackends/Vulkan/VulkanContext.cpp | 10 ++++++++++
 Source/Core/VideoCommon/DriverDetails.cpp          |  6 +++++-
 Source/Core/VideoCommon/DriverDetails.h            |  5 +++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp
index 6a8256b683..72eddd56c9 100644
--- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp
+++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp
@@ -775,6 +775,16 @@ u32 VulkanContext::GetReadbackMemoryType(u32 bits, bool* is_coherent)
 {
   std::optional<u32> type_index;
 
+  // Mali driver appears to be significantly slower for readbacks when using cached memory.
+  if (DriverDetails::HasBug(DriverDetails::BUG_SLOW_CACHED_READBACK_MEMORY))
+  {
+    type_index = GetMemoryType(
+        bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, true,
+        is_coherent);
+    if (type_index)
+      return type_index.value();
+  }
+
   // Optimal config uses cached+coherent.
   type_index =
       GetMemoryType(bits,
diff --git a/Source/Core/VideoCommon/DriverDetails.cpp b/Source/Core/VideoCommon/DriverDetails.cpp
index 0b04309702..1670f1a028 100644
--- a/Source/Core/VideoCommon/DriverDetails.cpp
+++ b/Source/Core/VideoCommon/DriverDetails.cpp
@@ -113,7 +113,11 @@ constexpr BugInfo m_known_bugs[] = {
     {API_VULKAN, OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN,
      BUG_BROKEN_REVERSED_DEPTH_RANGE, -1.0, -1.0, true},
     {API_VULKAN, OS_OSX, VENDOR_ALL, DRIVER_PORTABILITY, Family::UNKNOWN,
-     BUG_BROKEN_REVERSED_DEPTH_RANGE, -1.0, -1.0, true}};
+     BUG_BROKEN_REVERSED_DEPTH_RANGE, -1.0, -1.0, true},
+    {API_VULKAN, OS_ALL, VENDOR_ARM, DRIVER_ARM, Family::UNKNOWN, BUG_SLOW_CACHED_READBACK_MEMORY,
+     -1.0, -1.0, true},
+    {API_VULKAN, OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN,
+     BUG_SLOW_CACHED_READBACK_MEMORY, -1.0, -1.0, true}};
 
 static std::map<Bug, BugInfo> m_bugs;
 
diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h
index 4c0f280856..3e58a5fb58 100644
--- a/Source/Core/VideoCommon/DriverDetails.h
+++ b/Source/Core/VideoCommon/DriverDetails.h
@@ -281,6 +281,11 @@ enum Bug
   // The Vulkan spec allows the minDepth/maxDepth fields in the viewport to be reversed,
   // however the implementation is broken on some drivers.
   BUG_BROKEN_REVERSED_DEPTH_RANGE,
+
+  // BUG: Cached memory is significantly slower for readbacks than coherent memory in the
+  // Mali Vulkan driver, causing high CPU usage in the __pi___inval_cache_range kernel
+  // function. This flag causes readback buffers to select the coherent type.
+  BUG_SLOW_CACHED_READBACK_MEMORY,
 };
 
 // Initializes our internal vendor, device family, and driver version