From 7f4165fc056261820fe760629e6ac7b1f27de003 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 11 Nov 2021 19:15:51 -0800
Subject: [PATCH] hle: vi: Integrate new NVFlinger and HosBinderDriverServer
 service.

---
 src/core/hle/service/nvflinger/nvflinger.cpp  |  81 +-
 src/core/hle/service/nvflinger/nvflinger.h    |  27 +-
 src/core/hle/service/service.cpp              |   6 +-
 src/core/hle/service/service.h                |   4 +-
 .../hle/service/vi/display/vi_display.cpp     |  50 +-
 src/core/hle/service/vi/display/vi_display.h  |  29 +-
 src/core/hle/service/vi/layer/vi_layer.cpp    |   6 +-
 src/core/hle/service/vi/layer/vi_layer.h      |  57 +-
 src/core/hle/service/vi/vi.cpp                | 690 ++----------------
 src/core/hle/service/vi/vi.h                  |  10 +-
 src/core/hle/service/vi/vi_m.cpp              |   9 +-
 src/core/hle/service/vi/vi_m.h                |   7 +-
 src/core/hle/service/vi/vi_s.cpp              |   9 +-
 src/core/hle/service/vi/vi_s.h                |   7 +-
 src/core/hle/service/vi/vi_u.cpp              |   9 +-
 src/core/hle/service/vi/vi_u.h                |   7 +-
 src/video_core/gpu.h                          |   1 +
 17 files changed, 286 insertions(+), 723 deletions(-)

diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 01e69de30..e21dc902a 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -1,6 +1,5 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-License-Identifier: GPL-3.0-or-later
+// Copyright 2021 yuzu Emulator Project
 
 #include <algorithm>
 #include <optional>
@@ -16,8 +15,11 @@
 #include "core/hle/kernel/k_readable_event.h"
 #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
 #include "core/hle/service/nvdrv/nvdrv.h"
-#include "core/hle/service/nvflinger/buffer_queue.h"
+#include "core/hle/service/nvflinger/buffer_item_consumer.h"
+#include "core/hle/service/nvflinger/buffer_queue_core.h"
+#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
 #include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
 #include "core/hle/service/vi/display/vi_display.h"
 #include "core/hle/service/vi/layer/vi_layer.h"
 #include "video_core/gpu.h"
@@ -53,13 +55,14 @@ void NVFlinger::SplitVSync(std::stop_token stop_token) {
     }
 }
 
-NVFlinger::NVFlinger(Core::System& system_)
-    : system(system_), service_context(system_, "nvflinger") {
-    displays.emplace_back(0, "Default", service_context, system);
-    displays.emplace_back(1, "External", service_context, system);
-    displays.emplace_back(2, "Edid", service_context, system);
-    displays.emplace_back(3, "Internal", service_context, system);
-    displays.emplace_back(4, "Null", service_context, system);
+NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
+    : system(system_), service_context(system_, "nvflinger"),
+      hos_binder_driver_server(hos_binder_driver_server_) {
+    displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system);
+    displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system);
+    displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system);
+    displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system);
+    displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system);
     guard = std::make_shared<std::mutex>();
 
     // Schedule the screen composition events
@@ -83,12 +86,15 @@ NVFlinger::NVFlinger(Core::System& system_)
 }
 
 NVFlinger::~NVFlinger() {
-    for (auto& buffer_queue : buffer_queues) {
-        buffer_queue->Disconnect();
-    }
     if (!system.IsMulticore()) {
         system.CoreTiming().UnscheduleEvent(composition_event, 0);
     }
+
+    for (auto& display : displays) {
+        for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
+            display.GetLayer(layer).Core().NotifyShutdown();
+        }
+    }
 }
 
 void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@@ -125,10 +131,8 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
 }
 
 void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
-    const u32 buffer_queue_id = next_buffer_queue_id++;
-    buffer_queues.emplace_back(
-        std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id, service_context));
-    display.CreateLayer(layer_id, *buffer_queues.back());
+    const auto buffer_id = next_buffer_queue_id++;
+    display.CreateLayer(layer_id, buffer_id);
 }
 
 void NVFlinger::CloseLayer(u64 layer_id) {
@@ -147,7 +151,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
         return std::nullopt;
     }
 
-    return layer->GetBufferQueue().GetId();
+    return layer->GetBinderId();
 }
 
 Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
@@ -161,18 +165,6 @@ Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
     return &display->GetVSyncEvent();
 }
 
-BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
-    const auto lock_guard = Lock();
-    const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
-                                  [id](const auto& queue) { return queue->GetId() == id; });
-
-    if (itr == buffer_queues.end()) {
-        return nullptr;
-    }
-
-    return itr->get();
-}
-
 VI::Display* NVFlinger::FindDisplay(u64 display_id) {
     const auto itr =
         std::find_if(displays.begin(), displays.end(),
@@ -246,23 +238,22 @@ void NVFlinger::Compose() {
 
         // TODO(Subv): Support more than 1 layer.
         VI::Layer& layer = display.GetLayer(0);
-        auto& buffer_queue = layer.GetBufferQueue();
 
-        // Search for a queued buffer and acquire it
-        auto buffer = buffer_queue.AcquireBuffer();
+        android::BufferItem buffer{};
+        const auto status = layer.GetConsumer().AcquireBuffer(&buffer, 0, false);
 
-        if (!buffer) {
+        if (status != android::Status::NoError) {
             continue;
         }
 
-        const auto& igbp_buffer = buffer->get().igbp_buffer;
+        const auto& igbp_buffer = *buffer.graphic_buffer;
 
         if (!system.IsPoweredOn()) {
             return; // We are likely shutting down
         }
 
         auto& gpu = system.GPU();
-        const auto& multi_fence = buffer->get().multi_fence;
+        const auto& multi_fence = buffer.fence;
         guard->unlock();
         for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) {
             const auto& fence = multi_fence.fences[fence_id];
@@ -278,12 +269,18 @@ void NVFlinger::Compose() {
         auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
         ASSERT(nvdisp);
 
-        nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.external_format,
-                     igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
-                     buffer->get().transform, buffer->get().crop_rect);
+        Common::Rectangle<int> crop_rect{
+            static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()),
+            static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())};
 
-        swap_interval = buffer->get().swap_interval;
-        buffer_queue.ReleaseBuffer(buffer->get().slot);
+        nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(),
+                     igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(),
+                     static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect);
+
+        swap_interval = buffer.swap_interval;
+
+        auto fence = android::Fence::NoFence();
+        layer.GetConsumer().ReleaseBuffer(buffer, fence);
     }
 }
 
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 7935cf773..5112ae136 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -1,6 +1,5 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-License-Identifier: GPL-3.0-or-later
+// Copyright 2021 yuzu Emulator Project
 
 #pragma once
 
@@ -9,6 +8,7 @@
 #include <mutex>
 #include <optional>
 #include <thread>
+#include <unordered_map>
 #include <vector>
 
 #include "common/common_types.h"
@@ -37,13 +37,16 @@ class Display;
 class Layer;
 } // namespace Service::VI
 
-namespace Service::NVFlinger {
+namespace android {
+class BufferQueueCore;
+class BufferQueueProducer;
+} // namespace android
 
-class BufferQueue;
+namespace Service::NVFlinger {
 
 class NVFlinger final {
 public:
-    explicit NVFlinger(Core::System& system_);
+    explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
     ~NVFlinger();
 
     /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -72,15 +75,18 @@ public:
     /// If an invalid display ID is provided, then nullptr is returned.
     [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id);
 
-    /// Obtains a buffer queue identified by the ID.
-    [[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
-
     /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
     /// finished.
     void Compose();
 
     [[nodiscard]] s64 GetNextTicks() const;
 
+private:
+    struct Layer {
+        std::unique_ptr<android::BufferQueueCore> core;
+        std::unique_ptr<android::BufferQueueProducer> producer;
+    };
+
 private:
     [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
         return std::unique_lock{*guard};
@@ -111,7 +117,6 @@ private:
     std::shared_ptr<Nvidia::Module> nvdrv;
 
     std::list<VI::Display> displays;
-    std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
 
     /// Id to use for the next layer that is created, this counter is shared among all displays.
     u64 next_layer_id = 1;
@@ -131,6 +136,8 @@ private:
     std::jthread vsync_thread;
 
     KernelHelpers::ServiceContext service_context;
+
+    HosBinderDriverServer& hos_binder_driver_server;
 };
 
 } // namespace Service::NVFlinger
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index eb1138313..ab3286db9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -49,6 +49,7 @@
 #include "core/hle/service/npns/npns.h"
 #include "core/hle/service/ns/ns.h"
 #include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
 #include "core/hle/service/nvflinger/nvflinger.h"
 #include "core/hle/service/olsc/olsc.h"
 #include "core/hle/service/pcie/pcie.h"
@@ -230,7 +231,8 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& sessi
 
 /// Initialize Services
 Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
-    : nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} {
+    : hos_binder_driver_server{std::make_unique<NVFlinger::HosBinderDriverServer>(system)},
+      nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system, *hos_binder_driver_server)} {
 
     // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
     // here and pass it into the respective InstallInterfaces functions.
@@ -290,7 +292,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
     SSL::InstallInterfaces(*sm, system);
     Time::InstallInterfaces(system);
     USB::InstallInterfaces(*sm, system);
-    VI::InstallInterfaces(*sm, system, *nv_flinger);
+    VI::InstallInterfaces(*sm, system, *nv_flinger, *hos_binder_driver_server);
     WLAN::InstallInterfaces(*sm, system);
 }
 
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index c9d6b879d..b9ab2c465 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -33,8 +33,9 @@ class FileSystemController;
 }
 
 namespace NVFlinger {
+class HosBinderDriverServer;
 class NVFlinger;
-}
+} // namespace NVFlinger
 
 namespace SM {
 class ServiceManager;
@@ -236,6 +237,7 @@ public:
     ~Services();
 
 private:
+    std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server;
     std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
 };
 
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index b7705c02a..558022511 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -13,14 +13,34 @@
 #include "core/hle/kernel/k_readable_event.h"
 #include "core/hle/kernel/k_writable_event.h"
 #include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nvflinger/buffer_item_consumer.h"
+#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
+#include "core/hle/service/nvflinger/buffer_queue_core.h"
+#include "core/hle/service/nvflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
 #include "core/hle/service/vi/display/vi_display.h"
 #include "core/hle/service/vi/layer/vi_layer.h"
 
 namespace Service::VI {
 
-Display::Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_,
-                 Core::System& system_)
-    : display_id{id}, name{std::move(name_)}, service_context{service_context_} {
+struct BufferQueue {
+    std::shared_ptr<android::BufferQueueCore> core;
+    std::unique_ptr<android::BufferQueueProducer> producer;
+    std::unique_ptr<android::BufferQueueConsumer> consumer;
+};
+
+static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context) {
+    auto buffer_queue_core = std::make_shared<android::BufferQueueCore>();
+    return {buffer_queue_core,
+            std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core),
+            std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
+}
+
+Display::Display(u64 id, std::string name_,
+                 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
+                 KernelHelpers::ServiceContext& service_context_, Core::System& system_)
+    : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
+      service_context{service_context_} {
     vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
 }
 
@@ -44,21 +64,29 @@ void Display::SignalVSyncEvent() {
     vsync_event->GetWritableEvent().Signal();
 }
 
-void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) {
-    // TODO(Subv): Support more than 1 layer.
+void Display::CreateLayer(u64 layer_id, u32 binder_id) {
     ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
 
-    layers.emplace_back(std::make_shared<Layer>(layer_id, buffer_queue));
+    auto [core, producer, consumer] = CreateBufferQueue(service_context);
+
+    auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
+    buffer_item_consumer->Connect(false);
+
+    layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer,
+                                                std::move(buffer_item_consumer)));
+
+    hos_binder_driver_server.RegisterProducer(std::move(producer));
 }
 
 void Display::CloseLayer(u64 layer_id) {
-    std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetID() == layer_id; });
+    std::erase_if(layers,
+                  [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
 }
 
 Layer* Display::FindLayer(u64 layer_id) {
     const auto itr =
-        std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
-            return layer->GetID() == layer_id;
+        std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
+            return layer->GetLayerId() == layer_id;
         });
 
     if (itr == layers.end()) {
@@ -70,8 +98,8 @@ Layer* Display::FindLayer(u64 layer_id) {
 
 const Layer* Display::FindLayer(u64 layer_id) const {
     const auto itr =
-        std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
-            return layer->GetID() == layer_id;
+        std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
+            return layer->GetLayerId() == layer_id;
         });
 
     if (itr == layers.end()) {
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 329f4ba86..9cf324395 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -15,12 +15,17 @@ namespace Kernel {
 class KEvent;
 }
 
-namespace Service::NVFlinger {
-class BufferQueue;
+namespace android {
+class BufferQueueProducer;
 }
+
 namespace Service::KernelHelpers {
 class ServiceContext;
-} // namespace Service::KernelHelpers
+}
+
+namespace Service::NVFlinger {
+class HosBinderDriverServer;
+}
 
 namespace Service::VI {
 
@@ -35,12 +40,13 @@ public:
     /// Constructs a display with a given unique ID and name.
     ///
     /// @param id The unique ID for this display.
+    /// @param hos_binder_driver_server_ NVFlinger HOSBinderDriver server instance.
     /// @param service_context_ The ServiceContext for the owning service.
     /// @param name_ The name for this display.
     /// @param system_ The global system instance.
     ///
-    Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_,
-            Core::System& system_);
+    Display(u64 id, std::string name_, NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
+            KernelHelpers::ServiceContext& service_context_, Core::System& system_);
     ~Display();
 
     /// Gets the unique ID assigned to this display.
@@ -64,6 +70,10 @@ public:
     /// Gets a layer for this display based off an index.
     const Layer& GetLayer(std::size_t index) const;
 
+    std::size_t GetNumLayers() const {
+        return layers.size();
+    }
+
     /// Gets the readable vsync event.
     Kernel::KReadableEvent& GetVSyncEvent();
 
@@ -72,10 +82,10 @@ public:
 
     /// Creates and adds a layer to this display with the given ID.
     ///
-    /// @param layer_id     The ID to assign to the created layer.
-    /// @param buffer_queue The buffer queue for the layer instance to use.
+    /// @param layer_id The ID to assign to the created layer.
+    /// @param binder_id The ID assigned to the buffer queue.
     ///
-    void CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue);
+    void CreateLayer(u64 layer_id, u32 binder_id);
 
     /// Closes and removes a layer from this display with the given ID.
     ///
@@ -104,9 +114,10 @@ public:
 private:
     u64 display_id;
     std::string name;
+    NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
     KernelHelpers::ServiceContext& service_context;
 
-    std::vector<std::shared_ptr<Layer>> layers;
+    std::vector<std::unique_ptr<Layer>> layers;
     Kernel::KEvent* vsync_event{};
 };
 
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 9bc382587..93858e91f 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -6,7 +6,11 @@
 
 namespace Service::VI {
 
-Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {}
+Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
+             android::BufferQueueProducer& binder_,
+             std::shared_ptr<android::BufferItemConsumer>&& consumer_)
+    : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
+                                                                                    consumer_)} {}
 
 Layer::~Layer() = default;
 
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index ebdd85505..079ec4dda 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -4,11 +4,15 @@
 
 #pragma once
 
+#include <memory>
+
 #include "common/common_types.h"
 
-namespace Service::NVFlinger {
-class BufferQueue;
-}
+namespace android {
+class BufferItemConsumer;
+class BufferQueueCore;
+class BufferQueueProducer;
+} // namespace android
 
 namespace Service::VI {
 
@@ -17,10 +21,13 @@ class Layer {
 public:
     /// Constructs a layer with a given ID and buffer queue.
     ///
-    /// @param id    The ID to assign to this layer.
-    /// @param queue The buffer queue for this layer to use.
+    /// @param layer_id_ The ID to assign to this layer.
+    /// @param binder_id_ The binder ID to assign to this layer.
+    /// @param binder_ The buffer producer queue for this layer to use.
     ///
-    Layer(u64 id, NVFlinger::BufferQueue& queue);
+    Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
+          android::BufferQueueProducer& binder_,
+          std::shared_ptr<android::BufferItemConsumer>&& consumer_);
     ~Layer();
 
     Layer(const Layer&) = delete;
@@ -30,23 +37,47 @@ public:
     Layer& operator=(Layer&&) = delete;
 
     /// Gets the ID for this layer.
-    u64 GetID() const {
+    u64 GetLayerId() const {
         return layer_id;
     }
 
+    /// Gets the binder ID for this layer.
+    u32 GetBinderId() const {
+        return binder_id;
+    }
+
     /// Gets a reference to the buffer queue this layer is using.
-    NVFlinger::BufferQueue& GetBufferQueue() {
-        return buffer_queue;
+    android::BufferQueueProducer& GetBufferQueue() {
+        return binder;
     }
 
     /// Gets a const reference to the buffer queue this layer is using.
-    const NVFlinger::BufferQueue& GetBufferQueue() const {
-        return buffer_queue;
+    const android::BufferQueueProducer& GetBufferQueue() const {
+        return binder;
+    }
+
+    android::BufferItemConsumer& GetConsumer() {
+        return *consumer;
+    }
+
+    const android::BufferItemConsumer& GetConsumer() const {
+        return *consumer;
+    }
+
+    android::BufferQueueCore& Core() {
+        return core;
+    }
+
+    const android::BufferQueueCore& Core() const {
+        return core;
     }
 
 private:
-    u64 layer_id;
-    NVFlinger::BufferQueue& buffer_queue;
+    const u64 layer_id;
+    const u32 binder_id;
+    android::BufferQueueCore& core;
+    android::BufferQueueProducer& binder;
+    std::shared_ptr<android::BufferItemConsumer> consumer;
 };
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 75ee3e5e4..e49e1ae28 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -22,8 +22,11 @@
 #include "core/hle/kernel/k_readable_event.h"
 #include "core/hle/kernel/k_thread.h"
 #include "core/hle/service/nvdrv/nvdata.h"
-#include "core/hle/service/nvflinger/buffer_queue.h"
+#include "core/hle/service/nvflinger/binder.h"
+#include "core/hle/service/nvflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
 #include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/nvflinger/parcel.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/vi/vi.h"
 #include "core/hle/service/vi/vi_m.h"
@@ -57,447 +60,24 @@ struct DisplayInfo {
 };
 static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
 
-class Parcel {
+class NativeWindow final {
 public:
-    // This default size was chosen arbitrarily.
-    static constexpr std::size_t DefaultBufferSize = 0x40;
-    Parcel() : buffer(DefaultBufferSize) {}
-    explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {}
-    virtual ~Parcel() = default;
-
-    template <typename T>
-    T Read() {
-        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
-        ASSERT(read_index + sizeof(T) <= buffer.size());
-
-        T val;
-        std::memcpy(&val, buffer.data() + read_index, sizeof(T));
-        read_index += sizeof(T);
-        read_index = Common::AlignUp(read_index, 4);
-        return val;
-    }
-
-    template <typename T>
-    T ReadUnaligned() {
-        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
-        ASSERT(read_index + sizeof(T) <= buffer.size());
-
-        T val;
-        std::memcpy(&val, buffer.data() + read_index, sizeof(T));
-        read_index += sizeof(T);
-        return val;
-    }
-
-    std::vector<u8> ReadBlock(std::size_t length) {
-        ASSERT(read_index + length <= buffer.size());
-        const u8* const begin = buffer.data() + read_index;
-        const u8* const end = begin + length;
-        std::vector<u8> data(begin, end);
-        read_index += length;
-        read_index = Common::AlignUp(read_index, 4);
-        return data;
-    }
-
-    std::u16string ReadInterfaceToken() {
-        [[maybe_unused]] const u32 unknown = Read<u32_le>();
-        const u32 length = Read<u32_le>();
-
-        std::u16string token{};
-
-        for (u32 ch = 0; ch < length + 1; ++ch) {
-            token.push_back(ReadUnaligned<u16_le>());
-        }
-
-        read_index = Common::AlignUp(read_index, 4);
-
-        return token;
-    }
-
-    template <typename T>
-    void Write(const T& val) {
-        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
-
-        if (buffer.size() < write_index + sizeof(T)) {
-            buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
-        }
-
-        std::memcpy(buffer.data() + write_index, &val, sizeof(T));
-        write_index += sizeof(T);
-        write_index = Common::AlignUp(write_index, 4);
-    }
-
-    template <typename T>
-    void WriteObject(const T& val) {
-        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
-
-        const u32_le size = static_cast<u32>(sizeof(val));
-        Write(size);
-        // TODO(Subv): Support file descriptors.
-        Write<u32_le>(0); // Fd count.
-        Write(val);
-    }
-
-    void Deserialize() {
-        ASSERT(buffer.size() > sizeof(Header));
-
-        Header header{};
-        std::memcpy(&header, buffer.data(), sizeof(Header));
-
-        read_index = header.data_offset;
-        DeserializeData();
-    }
-
-    std::vector<u8> Serialize() {
-        ASSERT(read_index == 0);
-        write_index = sizeof(Header);
-
-        SerializeData();
-
-        Header header{};
-        header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
-        header.data_offset = sizeof(Header);
-        header.objects_size = 4;
-        header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
-        std::memcpy(buffer.data(), &header, sizeof(Header));
-
-        return buffer;
-    }
-
-protected:
-    virtual void SerializeData() {}
-
-    virtual void DeserializeData() {}
+    constexpr explicit NativeWindow(u32 id_) : id{id_} {}
 
 private:
-    struct Header {
-        u32_le data_size;
-        u32_le data_offset;
-        u32_le objects_size;
-        u32_le objects_offset;
-    };
-    static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
-
-    std::vector<u8> buffer;
-    std::size_t read_index = 0;
-    std::size_t write_index = 0;
-};
-
-class NativeWindow : public Parcel {
-public:
-    explicit NativeWindow(u32 id) {
-        data.id = id;
-    }
-    ~NativeWindow() override = default;
-
-protected:
-    void SerializeData() override {
-        Write(data);
-    }
-
-private:
-    struct Data {
-        u32_le magic = 2;
-        u32_le process_id = 1;
-        u32_le id;
-        INSERT_PADDING_WORDS(3);
-        std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
-        INSERT_PADDING_WORDS(2);
-    };
-    static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size");
-
-    Data data{};
-};
-
-class IGBPConnectRequestParcel : public Parcel {
-public:
-    explicit IGBPConnectRequestParcel(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 unk;
-        u32_le api;
-        u32_le producer_controlled_by_app;
-    };
-
-    Data data;
-};
-
-class IGBPConnectResponseParcel : public Parcel {
-public:
-    explicit IGBPConnectResponseParcel(u32 width, u32 height) {
-        data.width = width;
-        data.height = height;
-    }
-    ~IGBPConnectResponseParcel() override = default;
-
-protected:
-    void SerializeData() override {
-        Write(data);
-    }
-
-private:
-    struct Data {
-        u32_le width;
-        u32_le height;
-        u32_le transform_hint;
-        u32_le num_pending_buffers;
-        u32_le status;
-    };
-    static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
-
-    Data data{};
-};
-
-/// Represents a parcel containing one int '0' as its data
-/// Used by DetachBuffer and Disconnect
-class IGBPEmptyResponseParcel : public Parcel {
-protected:
-    void SerializeData() override {
-        Write(data);
-    }
-
-private:
-    struct Data {
-        u32_le unk_0{};
-    };
-
-    Data data{};
-};
-
-class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
-public:
-    explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer_)
-        : Parcel(std::move(buffer_)) {
-        Deserialize();
-    }
-
-    void DeserializeData() override {
-        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
-        data = Read<Data>();
-        if (data.contains_object != 0) {
-            buffer_container = Read<BufferContainer>();
-        }
-    }
-
-    struct Data {
-        u32_le slot;
-        u32_le contains_object;
-    };
-
-    struct BufferContainer {
-        u32_le graphic_buffer_length;
-        INSERT_PADDING_WORDS(1);
-        NVFlinger::IGBPBuffer buffer{};
-    };
-
-    Data data{};
-    BufferContainer buffer_container{};
-};
-
-class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
-protected:
-    void SerializeData() override {
-        // TODO(Subv): Find out what this means
-        Write<u32>(0);
-    }
-};
-
-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();
-    }
-
-    void DeserializeData() override {
-        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
-        data = Read<Data>();
-    }
-
-    struct Data {
-        u32_le pixel_format;
-        u32_le width;
-        u32_le height;
-        u32_le get_frame_timestamps;
-        u32_le usage;
-    };
-
-    Data data;
-};
-
-class IGBPDequeueBufferResponseParcel : public Parcel {
-public:
-    explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_)
-        : slot(slot_), multi_fence(multi_fence_) {}
-
-protected:
-    void SerializeData() override {
-        Write(slot);
-        Write<u32_le>(1);
-        WriteObject(multi_fence);
-        Write<u32_le>(0);
-    }
-
-    u32_le slot;
-    Service::Nvidia::MultiFence multi_fence;
-};
-
-class IGBPRequestBufferRequestParcel : public Parcel {
-public:
-    explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
-        Deserialize();
-    }
-
-    void DeserializeData() override {
-        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
-        slot = Read<u32_le>();
-    }
-
-    u32_le slot;
-};
-
-class IGBPRequestBufferResponseParcel : public Parcel {
-public:
-    explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {}
-    ~IGBPRequestBufferResponseParcel() override = default;
-
-protected:
-    void SerializeData() override {
-        // TODO(Subv): Figure out what this value means, writing non-zero here will make libnx
-        // try to read an IGBPBuffer object from the parcel.
-        Write<u32_le>(1);
-        WriteObject(buffer);
-        Write<u32_le>(0);
-    }
-
-    NVFlinger::IGBPBuffer buffer;
-};
-
-class IGBPQueueBufferRequestParcel : public Parcel {
-public:
-    explicit IGBPQueueBufferRequestParcel(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;
-        INSERT_PADDING_WORDS(3);
-        u32_le timestamp;
-        s32_le is_auto_timestamp;
-        s32_le crop_top;
-        s32_le crop_left;
-        s32_le crop_right;
-        s32_le crop_bottom;
-        s32_le scaling_mode;
-        NVFlinger::BufferQueue::BufferTransformFlags transform;
-        u32_le sticky_transform;
-        INSERT_PADDING_WORDS(1);
-        u32_le swap_interval;
-        Service::Nvidia::MultiFence multi_fence;
-
-        Common::Rectangle<int> GetCropRect() const {
-            return {crop_left, crop_top, crop_right, crop_bottom};
-        }
-    };
-    static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
-
-    Data data;
-};
-
-class IGBPQueueBufferResponseParcel : public Parcel {
-public:
-    explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) {
-        data.width = width;
-        data.height = height;
-    }
-    ~IGBPQueueBufferResponseParcel() override = default;
-
-protected:
-    void SerializeData() override {
-        Write(data);
-    }
-
-private:
-    struct Data {
-        u32_le width;
-        u32_le height;
-        u32_le transform_hint;
-        u32_le num_pending_buffers;
-        u32_le status;
-    };
-    static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
-
-    Data data{};
-};
-
-class IGBPQueryRequestParcel : public Parcel {
-public:
-    explicit IGBPQueryRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
-        Deserialize();
-    }
-
-    void DeserializeData() override {
-        [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
-        type = Read<u32_le>();
-    }
-
-    u32 type;
-};
-
-class IGBPQueryResponseParcel : public Parcel {
-public:
-    explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {}
-    ~IGBPQueryResponseParcel() override = default;
-
-protected:
-    void SerializeData() override {
-        Write(value);
-    }
-
-private:
-    u32_le value;
+    const u32 magic = 2;
+    const u32 process_id = 1;
+    const u32 id;
+    const INSERT_PADDING_WORDS(3);
+    const std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
+    const INSERT_PADDING_WORDS(2);
 };
+static_assert(sizeof(NativeWindow) == 0x28, "ParcelData has wrong size");
 
 class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
 public:
-    explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
-        : ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) {
+    explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
+        : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
         static const FunctionInfo functions[] = {
             {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
             {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
@@ -508,147 +88,16 @@ public:
     }
 
 private:
-    enum class TransactionId {
-        RequestBuffer = 1,
-        SetBufferCount = 2,
-        DequeueBuffer = 3,
-        DetachBuffer = 4,
-        DetachNextBuffer = 5,
-        AttachBuffer = 6,
-        QueueBuffer = 7,
-        CancelBuffer = 8,
-        Query = 9,
-        Connect = 10,
-        Disconnect = 11,
-
-        AllocateBuffers = 13,
-        SetPreallocatedBuffer = 14,
-
-        GetBufferHistory = 17
-    };
-
     void TransactParcel(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
         const u32 id = rp.Pop<u32>();
-        const auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
+        const auto transaction = static_cast<android::TransactionId>(rp.Pop<u32>());
         const u32 flags = rp.Pop<u32>();
 
         LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
                   transaction, flags);
 
-        auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
-
-        switch (transaction) {
-        case TransactionId::Connect: {
-            IGBPConnectRequestParcel request{ctx.ReadBuffer()};
-            IGBPConnectResponseParcel response{static_cast<u32>(DisplayResolution::UndockedWidth),
-                                               static_cast<u32>(DisplayResolution::UndockedHeight)};
-
-            buffer_queue.Connect();
-
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        case TransactionId::SetPreallocatedBuffer: {
-            IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
-
-            buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer);
-
-            IGBPSetPreallocatedBufferResponseParcel response{};
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        case TransactionId::DequeueBuffer: {
-            IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
-            const u32 width{request.data.width};
-            const u32 height{request.data.height};
-
-            do {
-                if (auto result = buffer_queue.DequeueBuffer(width, height); result) {
-                    // Buffer is available
-                    IGBPDequeueBufferResponseParcel response{result->first, *result->second};
-                    ctx.WriteBuffer(response.Serialize());
-                    break;
-                }
-            } while (buffer_queue.IsConnected());
-
-            break;
-        }
-        case TransactionId::RequestBuffer: {
-            IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
-
-            auto& buffer = buffer_queue.RequestBuffer(request.slot);
-            IGBPRequestBufferResponseParcel response{buffer};
-            ctx.WriteBuffer(response.Serialize());
-
-            break;
-        }
-        case TransactionId::QueueBuffer: {
-            IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
-
-            buffer_queue.QueueBuffer(request.data.slot, request.data.transform,
-                                     request.data.GetCropRect(), request.data.swap_interval,
-                                     request.data.multi_fence);
-
-            IGBPQueueBufferResponseParcel response{1280, 720};
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        case TransactionId::Query: {
-            IGBPQueryRequestParcel request{ctx.ReadBuffer()};
-
-            const u32 value =
-                buffer_queue.Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
-
-            IGBPQueryResponseParcel response{value};
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        case TransactionId::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: {
-            LOG_WARNING(Service_VI, "(STUBBED) called, transaction=Disconnect");
-            const auto buffer = ctx.ReadBuffer();
-
-            buffer_queue.Disconnect();
-
-            IGBPEmptyResponseParcel response{};
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        case TransactionId::DetachBuffer: {
-            const auto buffer = ctx.ReadBuffer();
-
-            IGBPEmptyResponseParcel response{};
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        case TransactionId::SetBufferCount: {
-            LOG_WARNING(Service_VI, "(STUBBED) called, transaction=SetBufferCount");
-            [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
-
-            IGBPEmptyResponseParcel response{};
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        case TransactionId::GetBufferHistory: {
-            LOG_WARNING(Service_VI, "(STUBBED) called, transaction=GetBufferHistory");
-            [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
-
-            IGBPEmptyResponseParcel response{};
-            ctx.WriteBuffer(response.Serialize());
-            break;
-        }
-        default:
-            ASSERT_MSG(false, "Unimplemented");
-        }
+        server.TryGetProducer(id)->Transact(ctx, transaction, flags);
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(ResultSuccess);
@@ -674,13 +123,13 @@ private:
 
         LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
 
-        // TODO(Subv): Find out what this actually is.
         IPC::ResponseBuilder rb{ctx, 2, 1};
         rb.Push(ResultSuccess);
-        rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent());
+        rb.PushCopyObjects(server.TryGetProducer(id)->GetNativeHandle());
     }
 
-    NVFlinger::NVFlinger& nv_flinger;
+private:
+    NVFlinger::HosBinderDriverServer& server;
 };
 
 class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
@@ -937,7 +386,40 @@ private:
 
 class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
 public:
-    explicit IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
+    IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
+                               NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+        : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_},
+          hos_binder_driver_server{hos_binder_driver_server_} {
+
+        static const FunctionInfo functions[] = {
+            {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
+            {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
+            {102, &IApplicationDisplayService::GetManagerDisplayService,
+             "GetManagerDisplayService"},
+            {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
+             "GetIndirectDisplayTransactionService"},
+            {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
+            {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
+            {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
+            {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
+            {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
+            {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
+            {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
+            {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
+            {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
+            {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
+            {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
+            {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
+            {2450, &IApplicationDisplayService::GetIndirectLayerImageMap,
+             "GetIndirectLayerImageMap"},
+            {2451, nullptr, "GetIndirectLayerImageCropMap"},
+            {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
+             "GetIndirectLayerImageRequiredMemoryInfo"},
+            {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
+            {5203, nullptr, "GetDisplayVsyncEventForDebug"},
+        };
+        RegisterHandlers(functions);
+    }
 
 private:
     enum class ConvertedScaleMode : u64 {
@@ -961,7 +443,7 @@ private:
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
         rb.Push(ResultSuccess);
-        rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger);
+        rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
     }
 
     void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
@@ -985,7 +467,7 @@ private:
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
         rb.Push(ResultSuccess);
-        rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger);
+        rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
     }
 
     void OpenDisplay(Kernel::HLERequestContext& ctx) {
@@ -1089,7 +571,7 @@ private:
     void ListDisplays(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_VI, "(STUBBED) called");
 
-        DisplayInfo display_info;
+        const DisplayInfo display_info;
         ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
         IPC::ResponseBuilder rb{ctx, 4};
         rb.Push(ResultSuccess);
@@ -1124,8 +606,8 @@ private:
             return;
         }
 
-        NativeWindow native_window{*buffer_queue_id};
-        const auto buffer_size = ctx.WriteBuffer(native_window.Serialize());
+        const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
+        const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
 
         IPC::ResponseBuilder rb{ctx, 4};
         rb.Push(ResultSuccess);
@@ -1170,8 +652,8 @@ private:
             return;
         }
 
-        NativeWindow native_window{*buffer_queue_id};
-        const auto buffer_size = ctx.WriteBuffer(native_window.Serialize());
+        const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
+        const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
 
         IPC::ResponseBuilder rb{ctx, 6};
         rb.Push(ResultSuccess);
@@ -1287,39 +769,9 @@ private:
     }
 
     NVFlinger::NVFlinger& nv_flinger;
+    NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
 };
 
-IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
-                                                       NVFlinger::NVFlinger& nv_flinger_)
-    : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_} {
-    static const FunctionInfo functions[] = {
-        {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
-        {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
-        {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"},
-        {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
-         "GetIndirectDisplayTransactionService"},
-        {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
-        {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
-        {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
-        {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
-        {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
-        {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
-        {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
-        {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
-        {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
-        {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
-        {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
-        {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
-        {2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"},
-        {2451, nullptr, "GetIndirectLayerImageCropMap"},
-        {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
-         "GetIndirectLayerImageRequiredMemoryInfo"},
-        {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
-        {5203, nullptr, "GetDisplayVsyncEventForDebug"},
-    };
-    RegisterHandlers(functions);
-}
-
 static bool IsValidServiceAccess(Permission permission, Policy policy) {
     if (permission == Permission::User) {
         return policy == Policy::User;
@@ -1333,7 +785,9 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
 }
 
 void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
-                                   NVFlinger::NVFlinger& nv_flinger, Permission permission) {
+                                   NVFlinger::NVFlinger& nv_flinger,
+                                   NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
+                                   Permission permission) {
     IPC::RequestParser rp{ctx};
     const auto policy = rp.PopEnum<Policy>();
 
@@ -1346,14 +800,18 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System&
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(ResultSuccess);
-    rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger);
+    rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server);
 }
 
 void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
-                       NVFlinger::NVFlinger& nv_flinger) {
-    std::make_shared<VI_M>(system, nv_flinger)->InstallAsService(service_manager);
-    std::make_shared<VI_S>(system, nv_flinger)->InstallAsService(service_manager);
-    std::make_shared<VI_U>(system, nv_flinger)->InstallAsService(service_manager);
+                       NVFlinger::NVFlinger& nv_flinger,
+                       NVFlinger::HosBinderDriverServer& hos_binder_driver_server) {
+    std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)
+        ->InstallAsService(service_manager);
+    std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)
+        ->InstallAsService(service_manager);
+    std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)
+        ->InstallAsService(service_manager);
 }
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 2fd7f8e61..d68f2646b 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -15,8 +15,9 @@ class HLERequestContext;
 }
 
 namespace Service::NVFlinger {
+class HosBinderDriverServer;
 class NVFlinger;
-}
+} // namespace Service::NVFlinger
 
 namespace Service::SM {
 class ServiceManager;
@@ -47,11 +48,14 @@ enum class Policy {
 
 namespace detail {
 void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
-                           NVFlinger::NVFlinger& nv_flinger, Permission permission);
+                           NVFlinger::NVFlinger& nv_flinger,
+                           NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
+                           Permission permission);
 } // namespace detail
 
 /// Registers all VI services with the specified service manager.
 void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
-                       NVFlinger::NVFlinger& nv_flinger);
+                       NVFlinger::NVFlinger& nv_flinger,
+                       NVFlinger::HosBinderDriverServer& hos_binder_driver_server);
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index 87db1c416..be0255f3d 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -8,8 +8,10 @@
 
 namespace Service::VI {
 
-VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
-    : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_} {
+VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
+           NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+    : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
+                                                                      hos_binder_driver_server_} {
     static const FunctionInfo functions[] = {
         {2, &VI_M::GetDisplayService, "GetDisplayService"},
         {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_M::~VI_M() = default;
 void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_VI, "called");
 
-    detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::Manager);
+    detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
+                                  Permission::Manager);
 }
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index d79c41beb..efbd34e09 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -15,20 +15,23 @@ class HLERequestContext;
 }
 
 namespace Service::NVFlinger {
+class HosBinderDriverServer;
 class NVFlinger;
-}
+} // namespace Service::NVFlinger
 
 namespace Service::VI {
 
 class VI_M final : public ServiceFramework<VI_M> {
 public:
-    explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
+    explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
+                  NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
     ~VI_M() override;
 
 private:
     void GetDisplayService(Kernel::HLERequestContext& ctx);
 
     NVFlinger::NVFlinger& nv_flinger;
+    NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
 };
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp
index 5cd22f7df..7996a6811 100644
--- a/src/core/hle/service/vi/vi_s.cpp
+++ b/src/core/hle/service/vi/vi_s.cpp
@@ -8,8 +8,10 @@
 
 namespace Service::VI {
 
-VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
-    : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_} {
+VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
+           NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+    : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
+                                                                      hos_binder_driver_server_} {
     static const FunctionInfo functions[] = {
         {1, &VI_S::GetDisplayService, "GetDisplayService"},
         {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_S::~VI_S() = default;
 void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_VI, "called");
 
-    detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::System);
+    detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
+                                  Permission::System);
 }
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h
index 5f1f8f290..3812c5061 100644
--- a/src/core/hle/service/vi/vi_s.h
+++ b/src/core/hle/service/vi/vi_s.h
@@ -15,20 +15,23 @@ class HLERequestContext;
 }
 
 namespace Service::NVFlinger {
+class HosBinderDriverServer;
 class NVFlinger;
-}
+} // namespace Service::NVFlinger
 
 namespace Service::VI {
 
 class VI_S final : public ServiceFramework<VI_S> {
 public:
-    explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
+    explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
+                  NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
     ~VI_S() override;
 
 private:
     void GetDisplayService(Kernel::HLERequestContext& ctx);
 
     NVFlinger::NVFlinger& nv_flinger;
+    NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
 };
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index 0079d51f0..57c888313 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -8,8 +8,10 @@
 
 namespace Service::VI {
 
-VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
-    : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_} {
+VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
+           NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+    : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
+                                                                      hos_binder_driver_server_} {
     static const FunctionInfo functions[] = {
         {0, &VI_U::GetDisplayService, "GetDisplayService"},
         {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_U::~VI_U() = default;
 void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_VI, "called");
 
-    detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::User);
+    detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
+                                  Permission::User);
 }
 
 } // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h
index 8e3885c73..b08e56576 100644
--- a/src/core/hle/service/vi/vi_u.h
+++ b/src/core/hle/service/vi/vi_u.h
@@ -15,20 +15,23 @@ class HLERequestContext;
 }
 
 namespace Service::NVFlinger {
+class HosBinderDriverServer;
 class NVFlinger;
-}
+} // namespace Service::NVFlinger
 
 namespace Service::VI {
 
 class VI_U final : public ServiceFramework<VI_U> {
 public:
-    explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
+    explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
+                  NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
     ~VI_U() override;
 
 private:
     void GetDisplayService(Kernel::HLERequestContext& ctx);
 
     NVFlinger::NVFlinger& nv_flinger;
+    NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
 };
 
 } // namespace Service::VI
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 26b8ea233..97c029140 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -8,6 +8,7 @@
 
 #include "common/bit_field.h"
 #include "common/common_types.h"
+#include "core/hle/service/nvdrv/nvdata.h"
 #include "video_core/cdma_pusher.h"
 #include "video_core/framebuffer_config.h"