From a5d853a9f8a19dedbc6cb77e8ca714f65819ad1d Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 17 Oct 2018 20:44:07 -0400
Subject: [PATCH] GPU: Invalidate destination address of kepler_memory writes.

---
 src/video_core/engines/kepler_memory.cpp | 11 ++++++++++-
 src/video_core/engines/kepler_memory.h   |  7 ++++++-
 src/video_core/gpu.cpp                   |  2 +-
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
index 66ae6332d4..585290d9ff 100644
--- a/src/video_core/engines/kepler_memory.cpp
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -5,10 +5,14 @@
 #include "common/logging/log.h"
 #include "core/memory.h"
 #include "video_core/engines/kepler_memory.h"
+#include "video_core/rasterizer_interface.h"
 
 namespace Tegra::Engines {
 
-KeplerMemory::KeplerMemory(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
+KeplerMemory::KeplerMemory(VideoCore::RasterizerInterface& rasterizer,
+                           MemoryManager& memory_manager)
+    : memory_manager(memory_manager), rasterizer{rasterizer} {}
+
 KeplerMemory::~KeplerMemory() = default;
 
 void KeplerMemory::WriteReg(u32 method, u32 value) {
@@ -37,6 +41,11 @@ void KeplerMemory::ProcessData(u32 data) {
     VAddr dest_address =
         *memory_manager.GpuToCpuAddress(address + state.write_offset * sizeof(u32));
 
+    // We have to invalidate the destination region to evict any outdated surfaces from the cache.
+    // We do this before actually writing the new data because the destination address might contain
+    // a dirty surface that will have to be written back to memory.
+    rasterizer.InvalidateRegion(dest_address, sizeof(u32));
+
     Memory::Write32(dest_address, data);
 
     state.write_offset++;
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index b0d0078cfb..bf4a13cffd 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -11,6 +11,10 @@
 #include "common/common_types.h"
 #include "video_core/memory_manager.h"
 
+namespace VideoCore {
+class RasterizerInterface;
+}
+
 namespace Tegra::Engines {
 
 #define KEPLERMEMORY_REG_INDEX(field_name)                                                         \
@@ -18,7 +22,7 @@ namespace Tegra::Engines {
 
 class KeplerMemory final {
 public:
-    KeplerMemory(MemoryManager& memory_manager);
+    KeplerMemory(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager);
     ~KeplerMemory();
 
     /// Write the value to the register identified by method.
@@ -72,6 +76,7 @@ public:
 
 private:
     MemoryManager& memory_manager;
+    VideoCore::RasterizerInterface& rasterizer;
 
     void ProcessData(u32 data);
 };
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 9ba7e35338..2d70a833b5 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -28,7 +28,7 @@ GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
     fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
     maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
     maxwell_dma = std::make_unique<Engines::MaxwellDMA>(*memory_manager);
-    kepler_memory = std::make_unique<Engines::KeplerMemory>(*memory_manager);
+    kepler_memory = std::make_unique<Engines::KeplerMemory>(rasterizer, *memory_manager);
 }
 
 GPU::~GPU() = default;