From cc3aa959265480e1990b10ee37ebf1c0ade3da64 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Thu, 27 Feb 2020 10:47:02 -0400
Subject: [PATCH] NVFlinger: Lock race condition between CPU, Host Timing,
 VSync.

---
 src/core/hle/service/nvflinger/nvflinger.cpp | 2 ++
 src/core/hle/service/nvflinger/nvflinger.h   | 7 +++++++
 src/core/hle/service/vi/vi.cpp               | 2 ++
 3 files changed, 11 insertions(+)

diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index aaf28995db..b97f713500 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -36,10 +36,12 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
     displays.emplace_back(2, "Edid", system);
     displays.emplace_back(3, "Internal", system);
     displays.emplace_back(4, "Null", system);
+    guard = std::make_shared<std::mutex>();
 
     // Schedule the screen composition events
     composition_event =
         Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 ns_late) {
+            Lock();
             Compose();
             const auto ticks = GetNextTicks();
             this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late),
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 57a21f33b6..02c081494d 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <mutex>
 #include <optional>
 #include <string>
 #include <string_view>
@@ -79,6 +80,10 @@ public:
 
     s64 GetNextTicks() const;
 
+    std::unique_lock<std::mutex> Lock() {
+        return std::unique_lock{*guard};
+    }
+
 private:
     /// Finds the display identified by the specified ID.
     VI::Display* FindDisplay(u64 display_id);
@@ -108,6 +113,8 @@ private:
     /// Event that handles screen composition.
     std::shared_ptr<Core::Timing::EventType> composition_event;
 
+    std::shared_ptr<std::mutex> guard;
+
     Core::System& system;
 };
 
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 46e14c2a3f..1570920746 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -511,6 +511,7 @@ private:
         LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
                   static_cast<u32>(transaction), flags);
 
+        nv_flinger->Lock();
         auto& buffer_queue = nv_flinger->FindBufferQueue(id);
 
         switch (transaction) {
@@ -550,6 +551,7 @@ private:
                     [=](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
                         Kernel::ThreadWakeupReason reason) {
                         // Repeat TransactParcel DequeueBuffer when a buffer is available
+                        nv_flinger->Lock();
                         auto& buffer_queue = nv_flinger->FindBufferQueue(id);
                         auto result = buffer_queue.DequeueBuffer(width, height);
                         ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");