From 1f186f34a29da8c4e39e3ad25fff1e4a39b33e85 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Mon, 12 Oct 2020 17:35:34 -0700
Subject: [PATCH] hle: service: vi: Implement BufferQueue::CancelBuffer.

- This is used by Super Mario 3D All-Stars.
---
 .../hle/service/nvflinger/buffer_queue.cpp    | 14 +++++
 src/core/hle/service/nvflinger/buffer_queue.h |  1 +
 src/core/hle/service/vi/vi.cpp                | 52 ++++++++++++++-----
 3 files changed, 53 insertions(+), 14 deletions(-)

diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 637b310d77..4f1e210b1b 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -99,6 +99,20 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
     queue_sequence.push_back(slot);
 }
 
+void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
+    const auto itr = std::find_if(queue.begin(), queue.end(),
+                                  [slot](const Buffer& buffer) { return buffer.slot == slot; });
+    ASSERT(itr != queue.end());
+    ASSERT(itr->status != Buffer::Status::Free);
+    itr->status = Buffer::Status::Free;
+    itr->multi_fence = multi_fence;
+    itr->swap_interval = 0;
+
+    free_buffers.push_back(slot);
+
+    buffer_wait_event.writable->Signal();
+}
+
 std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
     auto itr = queue.end();
     // Iterate to find a queued buffer matching the requested slot.
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8a837e5aa7..e7517c7e1f 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -95,6 +95,7 @@ public:
     void QueueBuffer(u32 slot, BufferTransformFlags transform,
                      const Common::Rectangle<int>& crop_rect, u32 swap_interval,
                      Service::Nvidia::MultiFence& multi_fence);
+    void CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence);
     std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
     void ReleaseBuffer(u32 slot);
     void Disconnect();
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d380c60fb8..5b0e371fe9 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -215,10 +215,9 @@ public:
     explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
         Deserialize();
     }
-    ~IGBPConnectRequestParcel() override = default;
 
     void DeserializeData() override {
-        std::u16string token = ReadInterfaceToken();
+        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
         data = Read<Data>();
     }
 
@@ -279,10 +278,9 @@ public:
         : Parcel(std::move(buffer)) {
         Deserialize();
     }
-    ~IGBPSetPreallocatedBufferRequestParcel() override = default;
 
     void DeserializeData() override {
-        std::u16string token = ReadInterfaceToken();
+        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
         data = Read<Data>();
         buffer = Read<NVFlinger::IGBPBuffer>();
     }
@@ -306,15 +304,40 @@ protected:
     }
 };
 
+class IGBPCancelBufferRequestParcel : public Parcel {
+public:
+    explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+        Deserialize();
+    }
+
+    void DeserializeData() override {
+        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
+        data = Read<Data>();
+    }
+
+    struct Data {
+        u32_le slot;
+        Service::Nvidia::MultiFence multi_fence;
+    };
+
+    Data data;
+};
+
+class IGBPCancelBufferResponseParcel : public Parcel {
+protected:
+    void SerializeData() override {
+        Write<u32>(0); // Success
+    }
+};
+
 class IGBPDequeueBufferRequestParcel : public Parcel {
 public:
     explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
         Deserialize();
     }
-    ~IGBPDequeueBufferRequestParcel() override = default;
 
     void DeserializeData() override {
-        std::u16string token = ReadInterfaceToken();
+        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
         data = Read<Data>();
     }
 
@@ -333,7 +356,6 @@ class IGBPDequeueBufferResponseParcel : public Parcel {
 public:
     explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence)
         : slot(slot), multi_fence(multi_fence) {}
-    ~IGBPDequeueBufferResponseParcel() override = default;
 
 protected:
     void SerializeData() override {
@@ -352,10 +374,9 @@ public:
     explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
         Deserialize();
     }
-    ~IGBPRequestBufferRequestParcel() override = default;
 
     void DeserializeData() override {
-        std::u16string token = ReadInterfaceToken();
+        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
         slot = Read<u32_le>();
     }
 
@@ -384,10 +405,9 @@ public:
     explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
         Deserialize();
     }
-    ~IGBPQueueBufferRequestParcel() override = default;
 
     void DeserializeData() override {
-        std::u16string token = ReadInterfaceToken();
+        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
         data = Read<Data>();
     }
 
@@ -447,10 +467,9 @@ public:
     explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
         Deserialize();
     }
-    ~IGBPQueryRequestParcel() override = default;
 
     void DeserializeData() override {
-        std::u16string token = ReadInterfaceToken();
+        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
         type = Read<u32_le>();
     }
 
@@ -596,7 +615,12 @@ private:
             break;
         }
         case TransactionId::CancelBuffer: {
-            LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
+            IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()};
+
+            buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence);
+
+            IGBPCancelBufferResponseParcel response{};
+            ctx.WriteBuffer(response.Serialize());
             break;
         }
         case TransactionId::Disconnect: {
-- 
GitLab