From 7b0d8bd1fbfd7d8fe4d939cb3b8649a29f61655c Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 6 Jun 2021 20:58:57 -0300
Subject: [PATCH] rasterizer: Update pages in batches

---
 src/video_core/rasterizer_accelerated.cpp | 56 +++++++++++++++++------
 1 file changed, 41 insertions(+), 15 deletions(-)

diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
index 6decd25462..4c95247022 100644
--- a/src/video_core/rasterizer_accelerated.cpp
+++ b/src/video_core/rasterizer_accelerated.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <atomic>
+
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/div_ceil.h"
@@ -10,35 +12,59 @@
 
 namespace VideoCore {
 
-RasterizerAccelerated::RasterizerAccelerated(Core::Memory::Memory& cpu_memory_)
-    : cpu_memory{cpu_memory_} {}
+using namespace Core::Memory;
+
+RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) : cpu_memory{cpu_memory_} {}
 
 RasterizerAccelerated::~RasterizerAccelerated() = default;
 
 void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
-    const auto page_end = Common::DivCeil(addr + size, Core::Memory::PAGE_SIZE);
-    for (auto page = addr >> Core::Memory::PAGE_BITS; page != page_end; ++page) {
-        auto& count = cached_pages.at(page >> 2).Count(page);
+    u64 uncache_begin = 0;
+    u64 cache_begin = 0;
+    u64 uncache_bytes = 0;
+    u64 cache_bytes = 0;
+
+    std::atomic_thread_fence(std::memory_order_acquire);
+    const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
+    for (u64 page = addr >> PAGE_BITS; page != page_end; ++page) {
+        std::atomic_uint16_t& count = cached_pages.at(page >> 2).Count(page);
 
         if (delta > 0) {
-            ASSERT_MSG(count < UINT16_MAX, "Count may overflow!");
+            ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!");
         } else if (delta < 0) {
-            ASSERT_MSG(count > 0, "Count may underflow!");
+            ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
         } else {
-            ASSERT_MSG(true, "Delta must be non-zero!");
+            ASSERT_MSG(false, "Delta must be non-zero!");
         }
 
         // Adds or subtracts 1, as count is a unsigned 8-bit value
-        count += static_cast<u16>(delta);
+        count.fetch_add(static_cast<u16>(delta), std::memory_order_release);
 
         // Assume delta is either -1 or 1
-        if (count == 0) {
-            cpu_memory.RasterizerMarkRegionCached(page << Core::Memory::PAGE_BITS,
-                                                  Core::Memory::PAGE_SIZE, false);
-        } else if (count == 1 && delta > 0) {
-            cpu_memory.RasterizerMarkRegionCached(page << Core::Memory::PAGE_BITS,
-                                                  Core::Memory::PAGE_SIZE, true);
+        if (count.load(std::memory_order::relaxed) == 0) {
+            if (uncache_bytes == 0) {
+                uncache_begin = page;
+            }
+            uncache_bytes += PAGE_SIZE;
+        } else if (uncache_bytes > 0) {
+            cpu_memory.RasterizerMarkRegionCached(uncache_begin << PAGE_BITS, uncache_bytes, false);
+            uncache_bytes = 0;
         }
+        if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
+            if (cache_bytes == 0) {
+                cache_begin = page;
+            }
+            cache_bytes += PAGE_SIZE;
+        } else if (cache_bytes > 0) {
+            cpu_memory.RasterizerMarkRegionCached(cache_begin << PAGE_BITS, cache_bytes, true);
+            cache_bytes = 0;
+        }
+    }
+    if (uncache_bytes > 0) {
+        cpu_memory.RasterizerMarkRegionCached(uncache_begin << PAGE_BITS, uncache_bytes, false);
+    }
+    if (cache_bytes > 0) {
+        cpu_memory.RasterizerMarkRegionCached(cache_begin << PAGE_BITS, cache_bytes, true);
     }
 }