From 6fce1414c3a899c3694fd05518101a82ff8060ce Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 11 Feb 2018 19:03:31 -0500
Subject: [PATCH] vi: Parse IGBPQueueBufferRequestParcel params and expose
 buffer flip vertical.

---
 .../service/nvdrv/devices/nvdisp_disp0.cpp    |  6 +++--
 .../hle/service/nvdrv/devices/nvdisp_disp0.h  |  4 ++-
 .../hle/service/nvflinger/buffer_queue.cpp    |  3 ++-
 src/core/hle/service/nvflinger/buffer_queue.h | 16 +++++++++++-
 src/core/hle/service/nvflinger/nvflinger.cpp  |  2 +-
 src/core/hle/service/vi/vi.cpp                | 26 +++++++++++++++----
 6 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 4d0ab844c..7674d332d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -20,15 +20,17 @@ u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector
 }
 
 void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
-                        u32 stride) {
+                        u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) {
     VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
     LOG_WARNING(Service,
                 "Drawing from address %llx offset %08X Width %u Height %u Stride %u Format %u",
                 addr, offset, width, height, stride, format);
 
     using PixelFormat = RendererBase::FramebufferInfo::PixelFormat;
+    using Flags = NVFlinger::BufferQueue::BufferTransformFlags;
+    const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV);
     const RendererBase::FramebufferInfo framebuffer_info{
-        addr, offset, width, height, stride, static_cast<PixelFormat>(format)};
+        addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical};
 
     Core::System::GetInstance().perf_stats.EndGameFrame();
     VideoCore::g_renderer->SwapBuffers(framebuffer_info);
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index f3cfc9925..66f56f23d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -8,6 +8,7 @@
 #include <vector>
 #include "common/common_types.h"
 #include "core/hle/service/nvdrv/devices/nvdevice.h"
+#include "core/hle/service/nvflinger/buffer_queue.h"
 
 namespace Service {
 namespace Nvidia {
@@ -23,7 +24,8 @@ public:
     u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
 
     /// Performs a screen flip, drawing the buffer pointed to by the handle.
-    void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride);
+    void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
+              NVFlinger::BufferQueue::BufferTransformFlags transform);
 
 private:
     std::shared_ptr<nvmap> nvmap_dev;
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index f90c7ca51..ff7b6b039 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -58,12 +58,13 @@ const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
     return itr->igbp_buffer;
 }
 
-void BufferQueue::QueueBuffer(u32 slot) {
+void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform) {
     auto itr = std::find_if(queue.begin(), queue.end(),
                             [&](const Buffer& buffer) { return buffer.slot == slot; });
     ASSERT(itr != queue.end());
     ASSERT(itr->status == Buffer::Status::Dequeued);
     itr->status = Buffer::Status::Queued;
+    itr->transform = transform;
 }
 
 boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() {
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 5c6719407..ef9732769 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -46,18 +46,32 @@ public:
     BufferQueue(u32 id, u64 layer_id);
     ~BufferQueue() = default;
 
+    enum class BufferTransformFlags : u32 {
+        /// Flip source image horizontally (around the vertical axis)
+        FlipH = 0x01,
+        /// Flip source image vertically (around the horizontal axis)
+        FlipV = 0x02,
+        /// Rotate source image 90 degrees clockwise
+        Rotate90 = 0x04,
+        /// Rotate source image 180 degrees
+        Roate180 = 0x03,
+        /// Rotate source image 270 degrees clockwise
+        Roate270 = 0x07,
+    };
+
     struct Buffer {
         enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 };
 
         u32 slot;
         Status status = Status::Free;
         IGBPBuffer igbp_buffer;
+        BufferTransformFlags transform;
     };
 
     void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
     u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height);
     const IGBPBuffer& RequestBuffer(u32 slot) const;
-    void QueueBuffer(u32 slot);
+    void QueueBuffer(u32 slot, BufferTransformFlags transform);
     boost::optional<const Buffer&> AcquireBuffer();
     void ReleaseBuffer(u32 slot);
     u32 Query(QueryType type);
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index fe622b986..2089462b7 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -145,7 +145,7 @@ void NVFlinger::Compose() {
         ASSERT(nvdisp);
 
         nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
-                     igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride);
+                     igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform);
 
         buffer_queue->ReleaseBuffer(buffer->slot);
     }
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 0262e830b..dd4d3e517 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -3,7 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
-
+#include <array>
 #include "common/alignment.h"
 #include "common/scope_exit.h"
 #include "core/core_timing.h"
@@ -325,13 +325,29 @@ public:
         data = Read<Data>();
     }
 
+    struct Fence {
+        u32_le id;
+        u32_le value;
+    };
+    static_assert(sizeof(Fence) == 8, "Fence has wrong size");
+
     struct Data {
         u32_le slot;
-        INSERT_PADDING_WORDS(2);
+        INSERT_PADDING_WORDS(3);
         u32_le timestamp;
-        INSERT_PADDING_WORDS(20);
+        s32_le is_auto_timestamp;
+        s32_le crop_left;
+        s32_le crop_top;
+        s32_le crop_right;
+        s32_le crop_bottom;
+        s32_le scaling_mode;
+        NVFlinger::BufferQueue::BufferTransformFlags transform;
+        u32_le sticky_transform;
+        INSERT_PADDING_WORDS(2);
+        u32_le fence_is_valid;
+        std::array<Fence, 2> fences;
     };
-    static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
+    static_assert(sizeof(Data) == 80, "ParcelData has wrong size");
 
     Data data;
 };
@@ -456,7 +472,7 @@ private:
         } else if (transaction == TransactionId::QueueBuffer) {
             IGBPQueueBufferRequestParcel request{input_data};
 
-            buffer_queue->QueueBuffer(request.data.slot);
+            buffer_queue->QueueBuffer(request.data.slot, request.data.transform);
 
             IGBPQueueBufferResponseParcel response{1280, 720};
             response_buffer = response.Serialize();