Преглед изворни кода

vi: manage resources independently of nvnflinger and refactor

Liam пре 2 година
родитељ
комит
812f23d05c
62 измењених фајлова са 1756 додато и 1490 уклоњено
  1. 16 6
      src/core/CMakeLists.txt
  2. 6 1
      src/core/core.cpp
  3. 34 43
      src/core/hle/service/am/display_layer_manager.cpp
  4. 5 8
      src/core/hle/service/am/display_layer_manager.h
  5. 0 7
      src/core/hle/service/nvdrv/nvdrv.h
  6. 3 20
      src/core/hle/service/nvnflinger/binder.h
  7. 1 1
      src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
  8. 1 1
      src/core/hle/service/nvnflinger/buffer_item_consumer.h
  9. 75 1
      src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
  10. 8 2
      src/core/hle/service/nvnflinger/buffer_queue_consumer.h
  11. 23 9
      src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
  12. 4 4
      src/core/hle/service/nvnflinger/buffer_queue_producer.h
  13. 1 1
      src/core/hle/service/nvnflinger/consumer_base.cpp
  14. 2 2
      src/core/hle/service/nvnflinger/consumer_base.h
  15. 51 0
      src/core/hle/service/nvnflinger/display.h
  16. 32 33
      src/core/hle/service/nvnflinger/hardware_composer.cpp
  17. 7 13
      src/core/hle/service/nvnflinger/hardware_composer.h
  18. 15 5
      src/core/hle/service/nvnflinger/hos_binder_driver.cpp
  19. 14 7
      src/core/hle/service/nvnflinger/hos_binder_driver.h
  20. 13 9
      src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
  21. 7 9
      src/core/hle/service/nvnflinger/hos_binder_driver_server.h
  22. 3 302
      src/core/hle/service/nvnflinger/nvnflinger.cpp
  23. 3 149
      src/core/hle/service/nvnflinger/nvnflinger.h
  24. 123 0
      src/core/hle/service/nvnflinger/surface_flinger.cpp
  25. 65 0
      src/core/hle/service/nvnflinger/surface_flinger.h
  26. 0 126
      src/core/hle/service/service.cpp
  27. 0 10
      src/core/hle/service/service.h
  28. 136 0
      src/core/hle/service/services.cpp
  29. 22 0
      src/core/hle/service/services.h
  30. 49 69
      src/core/hle/service/vi/application_display_service.cpp
  31. 18 13
      src/core/hle/service/vi/application_display_service.h
  32. 6 7
      src/core/hle/service/vi/application_root_service.cpp
  33. 3 10
      src/core/hle/service/vi/application_root_service.h
  34. 114 0
      src/core/hle/service/vi/conductor.cpp
  35. 57 0
      src/core/hle/service/vi/conductor.h
  36. 227 0
      src/core/hle/service/vi/container.cpp
  37. 92 0
      src/core/hle/service/vi/container.h
  38. 44 0
      src/core/hle/service/vi/display.h
  39. 0 143
      src/core/hle/service/vi/display/vi_display.cpp
  40. 0 143
      src/core/hle/service/vi/display/vi_display.h
  41. 83 0
      src/core/hle/service/vi/display_list.h
  42. 79 0
      src/core/hle/service/vi/layer.h
  43. 0 18
      src/core/hle/service/vi/layer/vi_layer.cpp
  44. 0 118
      src/core/hle/service/vi/layer/vi_layer.h
  45. 69 0
      src/core/hle/service/vi/layer_list.h
  46. 29 20
      src/core/hle/service/vi/manager_display_service.cpp
  47. 17 5
      src/core/hle/service/vi/manager_display_service.h
  48. 6 7
      src/core/hle/service/vi/manager_root_service.cpp
  49. 3 10
      src/core/hle/service/vi/manager_root_service.h
  50. 2 3
      src/core/hle/service/vi/service_creator.cpp
  51. 2 7
      src/core/hle/service/vi/service_creator.h
  52. 62 70
      src/core/hle/service/vi/shared_buffer_manager.cpp
  53. 25 16
      src/core/hle/service/vi/shared_buffer_manager.h
  54. 16 12
      src/core/hle/service/vi/system_display_service.cpp
  55. 5 11
      src/core/hle/service/vi/system_display_service.h
  56. 5 7
      src/core/hle/service/vi/system_root_service.cpp
  57. 3 10
      src/core/hle/service/vi/system_root_service.h
  58. 11 20
      src/core/hle/service/vi/vi.cpp
  59. 3 1
      src/core/hle/service/vi/vi.h
  60. 1 1
      src/core/hle/service/vi/vi_types.h
  61. 26 0
      src/core/hle/service/vi/vsync_manager.cpp
  62. 29 0
      src/core/hle/service/vi/vsync_manager.h

+ 16 - 6
src/core/CMakeLists.txt

@@ -813,6 +813,8 @@ add_library(core STATIC
     hle/service/nvnflinger/pixel_format.h
     hle/service/nvnflinger/pixel_format.h
     hle/service/nvnflinger/producer_listener.h
     hle/service/nvnflinger/producer_listener.h
     hle/service/nvnflinger/status.h
     hle/service/nvnflinger/status.h
+    hle/service/nvnflinger/surface_flinger.cpp
+    hle/service/nvnflinger/surface_flinger.h
     hle/service/nvnflinger/ui/fence.h
     hle/service/nvnflinger/ui/fence.h
     hle/service/nvnflinger/ui/graphic_buffer.cpp
     hle/service/nvnflinger/ui/graphic_buffer.cpp
     hle/service/nvnflinger/ui/graphic_buffer.h
     hle/service/nvnflinger/ui/graphic_buffer.h
@@ -906,6 +908,8 @@ add_library(core STATIC
     hle/service/server_manager.h
     hle/service/server_manager.h
     hle/service/service.cpp
     hle/service/service.cpp
     hle/service/service.h
     hle/service/service.h
+    hle/service/services.cpp
+    hle/service/services.h
     hle/service/set/setting_formats/appln_settings.cpp
     hle/service/set/setting_formats/appln_settings.cpp
     hle/service/set/setting_formats/appln_settings.h
     hle/service/set/setting_formats/appln_settings.h
     hle/service/set/setting_formats/device_settings.cpp
     hle/service/set/setting_formats/device_settings.cpp
@@ -953,22 +957,26 @@ add_library(core STATIC
     hle/service/ssl/ssl_backend.h
     hle/service/ssl/ssl_backend.h
     hle/service/usb/usb.cpp
     hle/service/usb/usb.cpp
     hle/service/usb/usb.h
     hle/service/usb/usb.h
-    hle/service/vi/display/vi_display.cpp
-    hle/service/vi/display/vi_display.h
-    hle/service/vi/layer/vi_layer.cpp
-    hle/service/vi/layer/vi_layer.h
     hle/service/vi/application_display_service.cpp
     hle/service/vi/application_display_service.cpp
     hle/service/vi/application_display_service.h
     hle/service/vi/application_display_service.h
     hle/service/vi/application_root_service.cpp
     hle/service/vi/application_root_service.cpp
     hle/service/vi/application_root_service.h
     hle/service/vi/application_root_service.h
-    hle/service/vi/fbshare_buffer_manager.cpp
-    hle/service/vi/fbshare_buffer_manager.h
+    hle/service/vi/conductor.cpp
+    hle/service/vi/conductor.h
+    hle/service/vi/container.cpp
+    hle/service/vi/container.h
+    hle/service/vi/display_list.h
+    hle/service/vi/display.h
+    hle/service/vi/layer_list.h
+    hle/service/vi/layer.h
     hle/service/vi/manager_display_service.cpp
     hle/service/vi/manager_display_service.cpp
     hle/service/vi/manager_display_service.h
     hle/service/vi/manager_display_service.h
     hle/service/vi/manager_root_service.cpp
     hle/service/vi/manager_root_service.cpp
     hle/service/vi/manager_root_service.h
     hle/service/vi/manager_root_service.h
     hle/service/vi/service_creator.cpp
     hle/service/vi/service_creator.cpp
     hle/service/vi/service_creator.h
     hle/service/vi/service_creator.h
+    hle/service/vi/shared_buffer_manager.cpp
+    hle/service/vi/shared_buffer_manager.h
     hle/service/vi/system_display_service.cpp
     hle/service/vi/system_display_service.cpp
     hle/service/vi/system_display_service.h
     hle/service/vi/system_display_service.h
     hle/service/vi/system_root_service.cpp
     hle/service/vi/system_root_service.cpp
@@ -977,6 +985,8 @@ add_library(core STATIC
     hle/service/vi/vi_types.h
     hle/service/vi/vi_types.h
     hle/service/vi/vi.cpp
     hle/service/vi/vi.cpp
     hle/service/vi/vi.h
     hle/service/vi/vi.h
+    hle/service/vi/vsync_manager.cpp
+    hle/service/vi/vsync_manager.h
     internal_network/network.cpp
     internal_network/network.cpp
     internal_network/network.h
     internal_network/network.h
     internal_network/network_interface.cpp
     internal_network/network_interface.cpp

+ 6 - 1
src/core/core.cpp

@@ -47,6 +47,7 @@
 #include "core/hle/service/psc/time/system_clock.h"
 #include "core/hle/service/psc/time/system_clock.h"
 #include "core/hle/service/psc/time/time_zone_service.h"
 #include "core/hle/service/psc/time/time_zone_service.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
+#include "core/hle/service/services.h"
 #include "core/hle/service/set/system_settings_server.h"
 #include "core/hle/service/set/system_settings_server.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/internal_network/network.h"
 #include "core/internal_network/network.h"
@@ -310,7 +311,8 @@ struct System::Impl {
         audio_core = std::make_unique<AudioCore::AudioCore>(system);
         audio_core = std::make_unique<AudioCore::AudioCore>(system);
 
 
         service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
         service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
-        services = std::make_unique<Service::Services>(service_manager, system);
+        services =
+            std::make_unique<Service::Services>(service_manager, system, stop_event.get_token());
 
 
         is_powered_on = true;
         is_powered_on = true;
         exit_locked = false;
         exit_locked = false;
@@ -458,6 +460,7 @@ struct System::Impl {
             gpu_core->NotifyShutdown();
             gpu_core->NotifyShutdown();
         }
         }
 
 
+        stop_event.request_stop();
         core_timing.SyncPause(false);
         core_timing.SyncPause(false);
         Network::CancelPendingSocketOperations();
         Network::CancelPendingSocketOperations();
         kernel.SuspendEmulation(true);
         kernel.SuspendEmulation(true);
@@ -478,6 +481,7 @@ struct System::Impl {
         cpu_manager.Shutdown();
         cpu_manager.Shutdown();
         debugger.reset();
         debugger.reset();
         kernel.Shutdown();
         kernel.Shutdown();
+        stop_event = {};
         Network::RestartSocketOperations();
         Network::RestartSocketOperations();
 
 
         if (auto room_member = room_network.GetRoomMember().lock()) {
         if (auto room_member = room_network.GetRoomMember().lock()) {
@@ -613,6 +617,7 @@ struct System::Impl {
 
 
     ExecuteProgramCallback execute_program_callback;
     ExecuteProgramCallback execute_program_callback;
     ExitCallback exit_callback;
     ExitCallback exit_callback;
+    std::stop_source stop_event;
 
 
     std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
     std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
     std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
     std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};

+ 34 - 43
src/core/hle/service/am/display_layer_manager.cpp

@@ -3,11 +3,12 @@
 
 
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/service/am/display_layer_manager.h"
 #include "core/hle/service/am/display_layer_manager.h"
-#include "core/hle/service/nvnflinger/hos_binder_driver.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hle/service/vi/application_display_service.h"
 #include "core/hle/service/vi/application_display_service.h"
-#include "core/hle/service/vi/fbshare_buffer_manager.h"
+#include "core/hle/service/vi/container.h"
+#include "core/hle/service/vi/manager_display_service.h"
 #include "core/hle/service/vi/manager_root_service.h"
 #include "core/hle/service/vi/manager_root_service.h"
+#include "core/hle/service/vi/shared_buffer_manager.h"
 #include "core/hle/service/vi/vi_results.h"
 #include "core/hle/service/vi/vi_results.h"
 #include "core/hle/service/vi/vi_types.h"
 #include "core/hle/service/vi/vi_types.h"
 
 
@@ -20,12 +21,10 @@ DisplayLayerManager::~DisplayLayerManager() {
 
 
 void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process,
 void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process,
                                      AppletId applet_id, LibraryAppletMode mode) {
                                      AppletId applet_id, LibraryAppletMode mode) {
-    m_surface_flinger = system.ServiceManager()
-                            .GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true)
-                            ->GetSurfaceFlinger();
     R_ASSERT(system.ServiceManager()
     R_ASSERT(system.ServiceManager()
                  .GetService<VI::IManagerRootService>("vi:m", true)
                  .GetService<VI::IManagerRootService>("vi:m", true)
                  ->GetDisplayService(&m_display_service, VI::Policy::Compositor));
                  ->GetDisplayService(&m_display_service, VI::Policy::Compositor));
+    R_ASSERT(m_display_service->GetManagerDisplayService(&m_manager_display_service));
 
 
     m_process = process;
     m_process = process;
     m_system_shared_buffer_id = 0;
     m_system_shared_buffer_id = 0;
@@ -37,46 +36,47 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro
 }
 }
 
 
 void DisplayLayerManager::Finalize() {
 void DisplayLayerManager::Finalize() {
-    if (!m_surface_flinger) {
+    if (!m_manager_display_service) {
         return;
         return;
     }
     }
 
 
     // Clean up managed layers.
     // Clean up managed layers.
     for (const auto& layer : m_managed_display_layers) {
     for (const auto& layer : m_managed_display_layers) {
-        m_surface_flinger->DestroyLayer(layer);
+        m_manager_display_service->DestroyManagedLayer(layer);
     }
     }
 
 
     for (const auto& layer : m_managed_display_recording_layers) {
     for (const auto& layer : m_managed_display_recording_layers) {
-        m_surface_flinger->DestroyLayer(layer);
+        m_manager_display_service->DestroyManagedLayer(layer);
     }
     }
 
 
     // Clean up shared layers.
     // Clean up shared layers.
     if (m_buffer_sharing_enabled) {
     if (m_buffer_sharing_enabled) {
-        m_display_service->GetSharedBufferManager()->Finalize(m_process);
+        m_manager_display_service->DestroySharedLayerSession(m_process);
     }
     }
 
 
-    m_surface_flinger = nullptr;
+    m_manager_display_service = nullptr;
+    m_display_service = nullptr;
 }
 }
 
 
-Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer) {
-    R_UNLESS(m_surface_flinger != nullptr, VI::ResultOperationFailed);
+Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
+    R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
 
 
     // TODO(Subv): Find out how AM determines the display to use, for now just
     // TODO(Subv): Find out how AM determines the display to use, for now just
     // create the layer in the Default display.
     // create the layer in the Default display.
-    const auto display_id = m_surface_flinger->OpenDisplay("Default");
-    const auto layer_id = m_surface_flinger->CreateLayer(*display_id);
+    u64 display_id;
+    R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
+    R_TRY(m_manager_display_service->CreateManagedLayer(
+        out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
 
 
-    m_surface_flinger->SetLayerVisibility(*layer_id, m_visible);
-    m_managed_display_layers.emplace(*layer_id);
-
-    *out_layer = *layer_id;
+    m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
+    m_managed_display_layers.emplace(*out_layer_id);
 
 
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
-Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer,
-                                                               u64* out_recording_layer) {
-    R_UNLESS(m_surface_flinger != nullptr, VI::ResultOperationFailed);
+Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer_id,
+                                                               u64* out_recording_layer_id) {
+    R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
 
 
     // TODO(Subv): Find out how AM determines the display to use, for now just
     // TODO(Subv): Find out how AM determines the display to use, for now just
     // create the layer in the Default display.
     // create the layer in the Default display.
@@ -84,17 +84,8 @@ Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer,
     // Currently we do not support more than 1 layer per display, output 1 layer id for now.
     // Currently we do not support more than 1 layer per display, output 1 layer id for now.
     // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
     // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
     // side effects.
     // side effects.
-    // TODO: Support multiple layers
-    const auto display_id = m_surface_flinger->OpenDisplay("Default");
-    const auto layer_id = m_surface_flinger->CreateLayer(*display_id);
-
-    m_surface_flinger->SetLayerVisibility(*layer_id, m_visible);
-    m_managed_display_layers.emplace(*layer_id);
-
-    *out_layer = *layer_id;
-    *out_recording_layer = 0;
-
-    R_SUCCEED();
+    *out_recording_layer_id = 0;
+    R_RETURN(this->CreateManagedDisplayLayer(out_layer_id));
 }
 }
 
 
 Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
 Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
@@ -102,19 +93,19 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
     R_SUCCEED_IF(m_buffer_sharing_enabled);
     R_SUCCEED_IF(m_buffer_sharing_enabled);
 
 
     // Ensure we can access shared layers.
     // Ensure we can access shared layers.
-    R_UNLESS(m_surface_flinger != nullptr, VI::ResultOperationFailed);
+    R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
     R_UNLESS(m_applet_id != AppletId::Application, VI::ResultPermissionDenied);
     R_UNLESS(m_applet_id != AppletId::Application, VI::ResultPermissionDenied);
 
 
     // Create the shared layer.
     // Create the shared layer.
-    const auto blend =
-        m_blending_enabled ? Nvnflinger::LayerBlending::Coverage : Nvnflinger::LayerBlending::None;
-    const auto display_id = m_surface_flinger->OpenDisplay("Default").value();
-    R_TRY(m_display_service->GetSharedBufferManager()->Initialize(
-        m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blend));
+    u64 display_id;
+    R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
+    R_TRY(m_manager_display_service->CreateSharedLayerSession(m_process, &m_system_shared_buffer_id,
+                                                              &m_system_shared_layer_id, display_id,
+                                                              m_blending_enabled));
 
 
     // We succeeded, so set up remaining state.
     // We succeeded, so set up remaining state.
     m_buffer_sharing_enabled = true;
     m_buffer_sharing_enabled = true;
-    m_surface_flinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
+    m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
@@ -135,13 +126,13 @@ void DisplayLayerManager::SetWindowVisibility(bool visible) {
 
 
     m_visible = visible;
     m_visible = visible;
 
 
-    if (m_surface_flinger) {
+    if (m_manager_display_service) {
         if (m_system_shared_layer_id) {
         if (m_system_shared_layer_id) {
-            m_surface_flinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
+            m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
         }
         }
 
 
         for (const auto layer_id : m_managed_display_layers) {
         for (const auto layer_id : m_managed_display_layers) {
-            m_surface_flinger->SetLayerVisibility(layer_id, m_visible);
+            m_manager_display_service->SetLayerVisibility(m_visible, layer_id);
         }
         }
     }
     }
 }
 }
@@ -153,7 +144,7 @@ bool DisplayLayerManager::GetWindowVisibility() const {
 Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
 Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
                                                      s32* out_fbshare_layer_index) {
                                                      s32* out_fbshare_layer_index) {
     R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
     R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
-    R_RETURN(m_display_service->GetSharedBufferManager()->WriteAppletCaptureBuffer(
+    R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
         out_was_written, out_fbshare_layer_index));
         out_was_written, out_fbshare_layer_index));
 }
 }
 
 

+ 5 - 8
src/core/hle/service/am/display_layer_manager.h

@@ -17,13 +17,10 @@ namespace Kernel {
 class KProcess;
 class KProcess;
 }
 }
 
 
-namespace Service::Nvnflinger {
-class Nvnflinger;
-}
-
 namespace Service::VI {
 namespace Service::VI {
 class IApplicationDisplayService;
 class IApplicationDisplayService;
-}
+class IManagerDisplayService;
+} // namespace Service::VI
 
 
 namespace Service::AM {
 namespace Service::AM {
 
 
@@ -36,8 +33,8 @@ public:
                     LibraryAppletMode mode);
                     LibraryAppletMode mode);
     void Finalize();
     void Finalize();
 
 
-    Result CreateManagedDisplayLayer(u64* out_layer);
-    Result CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
+    Result CreateManagedDisplayLayer(u64* out_layer_id);
+    Result CreateManagedDisplaySeparableLayer(u64* out_layer_id, u64* out_recording_layer_id);
 
 
     Result IsSystemBufferSharingEnabled();
     Result IsSystemBufferSharingEnabled();
     Result GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
     Result GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
@@ -50,8 +47,8 @@ public:
 
 
 private:
 private:
     Kernel::KProcess* m_process{};
     Kernel::KProcess* m_process{};
-    std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger{};
     std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
     std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
+    std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
     std::set<u64> m_managed_display_layers{};
     std::set<u64> m_managed_display_layers{};
     std::set<u64> m_managed_display_recording_layers{};
     std::set<u64> m_managed_display_recording_layers{};
     u64 m_system_shared_buffer_id{};
     u64 m_system_shared_buffer_id{};

+ 0 - 7
src/core/hle/service/nvdrv/nvdrv.h

@@ -10,13 +10,11 @@
 #include <span>
 #include <span>
 #include <string>
 #include <string>
 #include <unordered_map>
 #include <unordered_map>
-#include <vector>
 
 
 #include "common/common_types.h"
 #include "common/common_types.h"
 #include "core/hle/service/kernel_helpers.h"
 #include "core/hle/service/kernel_helpers.h"
 #include "core/hle/service/nvdrv/core/container.h"
 #include "core/hle/service/nvdrv/core/container.h"
 #include "core/hle/service/nvdrv/nvdata.h"
 #include "core/hle/service/nvdrv/nvdata.h"
-#include "core/hle/service/nvnflinger/ui/fence.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
 
 
 namespace Core {
 namespace Core {
@@ -27,10 +25,6 @@ namespace Kernel {
 class KEvent;
 class KEvent;
 }
 }
 
 
-namespace Service::Nvnflinger {
-class Nvnflinger;
-}
-
 namespace Service::Nvidia {
 namespace Service::Nvidia {
 
 
 namespace NvCore {
 namespace NvCore {
@@ -99,7 +93,6 @@ public:
 
 
 private:
 private:
     friend class EventInterface;
     friend class EventInterface;
-    friend class Service::Nvnflinger::Nvnflinger;
 
 
     /// Manages syncpoints on the host
     /// Manages syncpoints on the host
     NvCore::Container container;
     NvCore::Container container;

+ 3 - 20
src/core/hle/service/nvnflinger/binder.h

@@ -20,29 +20,12 @@ class HLERequestContext;
 
 
 namespace Service::android {
 namespace Service::android {
 
 
-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,
-};
-
 class IBinder {
 class IBinder {
 public:
 public:
     virtual ~IBinder() = default;
     virtual ~IBinder() = default;
-    virtual void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data,
-                          std::span<u8> parcel_reply) = 0;
-    virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
+    virtual void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
+                          u32 flags) = 0;
+    virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0;
 };
 };
 
 
 } // namespace Service::android
 } // namespace Service::android

+ 1 - 1
src/core/hle/service/nvnflinger/buffer_item_consumer.cpp

@@ -12,7 +12,7 @@
 
 
 namespace Service::android {
 namespace Service::android {
 
 
-BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_)
+BufferItemConsumer::BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer_)
     : ConsumerBase{std::move(consumer_)} {}
     : ConsumerBase{std::move(consumer_)} {}
 
 
 Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
 Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,

+ 1 - 1
src/core/hle/service/nvnflinger/buffer_item_consumer.h

@@ -19,7 +19,7 @@ class BufferItem;
 
 
 class BufferItemConsumer final : public ConsumerBase {
 class BufferItemConsumer final : public ConsumerBase {
 public:
 public:
-    explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer);
+    explicit BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer);
     Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
     Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
                          bool wait_for_fence = true);
                          bool wait_for_fence = true);
     Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence);
     Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence);

+ 75 - 1
src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp

@@ -4,12 +4,13 @@
 // Parts of this implementation were based on:
 // Parts of this implementation were based on:
 // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
 // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
 
 
+#include "common/assert.h"
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/hle/service/nvnflinger/buffer_item.h"
 #include "core/hle/service/nvnflinger/buffer_item.h"
 #include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
 #include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
 #include "core/hle/service/nvnflinger/buffer_queue_core.h"
 #include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/parcel.h"
 #include "core/hle/service/nvnflinger/producer_listener.h"
 #include "core/hle/service/nvnflinger/producer_listener.h"
-#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 
 
 namespace Service::android {
 namespace Service::android {
 
 
@@ -254,4 +255,77 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
     return Status::NoError;
     return Status::NoError;
 }
 }
 
 
+void BufferQueueConsumer::Transact(u32 code, std::span<const u8> parcel_data,
+                                   std::span<u8> parcel_reply, u32 flags) {
+    // Values used by BnGraphicBufferConsumer onTransact
+    enum class TransactionId {
+        AcquireBuffer = 1,
+        DetachBuffer = 2,
+        AttachBuffer = 3,
+        ReleaseBuffer = 4,
+        ConsumerConnect = 5,
+        ConsumerDisconnect = 6,
+        GetReleasedBuffers = 7,
+        SetDefaultBufferSize = 8,
+        SetDefaultMaxBufferCount = 9,
+        DisableAsyncBuffer = 10,
+        SetMaxAcquiredBufferCount = 11,
+        SetConsumerName = 12,
+        SetDefaultBufferFormat = 13,
+        SetConsumerUsageBits = 14,
+        SetTransformHint = 15,
+        GetSidebandStream = 16,
+        Unknown18 = 18,
+        Unknown20 = 20,
+    };
+
+    Status status{Status::NoError};
+    InputParcel parcel_in{parcel_data};
+    OutputParcel parcel_out{};
+
+    switch (static_cast<TransactionId>(code)) {
+    case TransactionId::AcquireBuffer: {
+        BufferItem item;
+        const s64 present_when = parcel_in.Read<s64>();
+
+        status = AcquireBuffer(&item, std::chrono::nanoseconds{present_when});
+
+        // TODO: can't write this directly, needs a flattener for the sp<GraphicBuffer>
+        // parcel_out.WriteFlattened(item);
+        UNREACHABLE();
+    }
+    case TransactionId::ReleaseBuffer: {
+        const s32 slot = parcel_in.Read<s32>();
+        const u64 frame_number = parcel_in.Read<u64>();
+        const auto release_fence = parcel_in.ReadFlattened<Fence>();
+
+        status = ReleaseBuffer(slot, frame_number, release_fence);
+
+        break;
+    }
+    case TransactionId::GetReleasedBuffers: {
+        u64 slot_mask = 0;
+
+        status = GetReleasedBuffers(&slot_mask);
+
+        parcel_out.Write(slot_mask);
+        break;
+    }
+    default:
+        ASSERT_MSG(false, "called, code={} flags={}", code, flags);
+        break;
+    }
+
+    parcel_out.Write(status);
+
+    const auto serialized = parcel_out.Serialize();
+    std::memcpy(parcel_reply.data(), serialized.data(),
+                std::min(parcel_reply.size(), serialized.size()));
+}
+
+Kernel::KReadableEvent* BufferQueueConsumer::GetNativeHandle(u32 type_id) {
+    ASSERT_MSG(false, "called, type_id={}", type_id);
+    return nullptr;
+}
+
 } // namespace Service::android
 } // namespace Service::android

+ 8 - 2
src/core/hle/service/nvnflinger/buffer_queue_consumer.h

@@ -10,6 +10,7 @@
 #include <memory>
 #include <memory>
 
 
 #include "common/common_types.h"
 #include "common/common_types.h"
+#include "core/hle/service/nvnflinger/binder.h"
 #include "core/hle/service/nvnflinger/buffer_queue_defs.h"
 #include "core/hle/service/nvnflinger/buffer_queue_defs.h"
 #include "core/hle/service/nvnflinger/status.h"
 #include "core/hle/service/nvnflinger/status.h"
 
 
@@ -19,10 +20,10 @@ class BufferItem;
 class BufferQueueCore;
 class BufferQueueCore;
 class IConsumerListener;
 class IConsumerListener;
 
 
-class BufferQueueConsumer final {
+class BufferQueueConsumer final : public IBinder {
 public:
 public:
     explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
     explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
-    ~BufferQueueConsumer();
+    ~BufferQueueConsumer() override;
 
 
     Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
     Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
     Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
     Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
@@ -30,6 +31,11 @@ public:
     Status Disconnect();
     Status Disconnect();
     Status GetReleasedBuffers(u64* out_slot_mask);
     Status GetReleasedBuffers(u64* out_slot_mask);
 
 
+    void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
+                  u32 flags) override;
+
+    Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
+
 private:
 private:
     std::shared_ptr<BufferQueueCore> core;
     std::shared_ptr<BufferQueueCore> core;
     BufferQueueDefs::SlotsType& slots;
     BufferQueueDefs::SlotsType& slots;

+ 23 - 9
src/core/hle/service/nvnflinger/buffer_queue_producer.cpp

@@ -6,12 +6,9 @@
 
 
 #include "common/assert.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "common/logging/log.h"
-#include "common/settings.h"
-#include "core/core.h"
 #include "core/hle/kernel/k_event.h"
 #include "core/hle/kernel/k_event.h"
 #include "core/hle/kernel/k_readable_event.h"
 #include "core/hle/kernel/k_readable_event.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/kernel.h"
-#include "core/hle/service/hle_ipc.h"
 #include "core/hle/service/kernel_helpers.h"
 #include "core/hle/service/kernel_helpers.h"
 #include "core/hle/service/nvnflinger/buffer_queue_core.h"
 #include "core/hle/service/nvnflinger/buffer_queue_core.h"
 #include "core/hle/service/nvnflinger/buffer_queue_producer.h"
 #include "core/hle/service/nvnflinger/buffer_queue_producer.h"
@@ -19,7 +16,6 @@
 #include "core/hle/service/nvnflinger/parcel.h"
 #include "core/hle/service/nvnflinger/parcel.h"
 #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 #include "core/hle/service/nvnflinger/window.h"
 #include "core/hle/service/nvnflinger/window.h"
-#include "core/hle/service/vi/vi.h"
 
 
 namespace Service::android {
 namespace Service::android {
 
 
@@ -807,13 +803,31 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
     return Status::NoError;
     return Status::NoError;
 }
 }
 
 
-void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<const u8> parcel_data,
-                                   std::span<u8> parcel_reply) {
+void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
+                                   std::span<u8> parcel_reply, u32 flags) {
+    // Values used by BnGraphicBufferProducer onTransact
+    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,
+    };
+
     Status status{Status::NoError};
     Status status{Status::NoError};
     InputParcel parcel_in{parcel_data};
     InputParcel parcel_in{parcel_data};
     OutputParcel parcel_out{};
     OutputParcel parcel_out{};
 
 
-    switch (code) {
+    switch (static_cast<TransactionId>(code)) {
     case TransactionId::Connect: {
     case TransactionId::Connect: {
         const auto enable_listener = parcel_in.Read<bool>();
         const auto enable_listener = parcel_in.Read<bool>();
         const auto api = parcel_in.Read<NativeWindowApi>();
         const auto api = parcel_in.Read<NativeWindowApi>();
@@ -923,8 +937,8 @@ void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<cons
                 std::min(parcel_reply.size(), serialized.size()));
                 std::min(parcel_reply.size(), serialized.size()));
 }
 }
 
 
-Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() {
-    return buffer_wait_event->GetReadableEvent();
+Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
+    return &buffer_wait_event->GetReadableEvent();
 }
 }
 
 
 } // namespace Service::android
 } // namespace Service::android

+ 4 - 4
src/core/hle/service/nvnflinger/buffer_queue_producer.h

@@ -45,12 +45,12 @@ public:
     explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
     explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
                                  std::shared_ptr<BufferQueueCore> buffer_queue_core_,
                                  std::shared_ptr<BufferQueueCore> buffer_queue_core_,
                                  Service::Nvidia::NvCore::NvMap& nvmap_);
                                  Service::Nvidia::NvCore::NvMap& nvmap_);
-    ~BufferQueueProducer();
+    ~BufferQueueProducer() override;
 
 
-    void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data,
-                  std::span<u8> parcel_reply) override;
+    void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
+                  u32 flags) override;
 
 
-    Kernel::KReadableEvent& GetNativeHandle() override;
+    Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
 
 
 public:
 public:
     Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);
     Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);

+ 1 - 1
src/core/hle/service/nvnflinger/consumer_base.cpp

@@ -14,7 +14,7 @@
 
 
 namespace Service::android {
 namespace Service::android {
 
 
-ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_)
+ConsumerBase::ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_)
     : consumer{std::move(consumer_)} {}
     : consumer{std::move(consumer_)} {}
 
 
 ConsumerBase::~ConsumerBase() {
 ConsumerBase::~ConsumerBase() {

+ 2 - 2
src/core/hle/service/nvnflinger/consumer_base.h

@@ -27,7 +27,7 @@ public:
     void Abandon();
     void Abandon();
 
 
 protected:
 protected:
-    explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
+    explicit ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_);
     ~ConsumerBase() override;
     ~ConsumerBase() override;
 
 
     void OnFrameAvailable(const BufferItem& item) override;
     void OnFrameAvailable(const BufferItem& item) override;
@@ -54,7 +54,7 @@ protected:
 
 
     bool is_abandoned{};
     bool is_abandoned{};
 
 
-    std::unique_ptr<BufferQueueConsumer> consumer;
+    std::shared_ptr<BufferQueueConsumer> consumer;
 
 
     mutable std::mutex mutex;
     mutable std::mutex mutex;
 };
 };

+ 51 - 0
src/core/hle/service/nvnflinger/display.h

@@ -0,0 +1,51 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <list>
+
+#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
+#include "core/hle/service/nvnflinger/hwc_layer.h"
+
+namespace Service::Nvnflinger {
+
+struct Layer {
+    explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
+                   s32 consumer_id_)
+        : buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
+          blending(LayerBlending::None), visible(true) {}
+    ~Layer() {
+        buffer_item_consumer->Abandon();
+    }
+
+    std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer;
+    s32 consumer_id;
+    LayerBlending blending;
+    bool visible;
+};
+
+struct LayerStack {
+    std::list<Layer> layers;
+};
+
+struct Display {
+    explicit Display(u64 id_) {
+        id = id_;
+    }
+
+    Layer* FindLayer(s32 consumer_id) {
+        for (auto& layer : stack.layers) {
+            if (layer.consumer_id == consumer_id) {
+                return &layer;
+            }
+        }
+
+        return nullptr;
+    }
+
+    u64 id;
+    LayerStack stack;
+};
+
+} // namespace Service::Nvnflinger

+ 32 - 33
src/core/hle/service/nvnflinger/hardware_composer.cpp

@@ -10,8 +10,6 @@
 #include "core/hle/service/nvnflinger/hardware_composer.h"
 #include "core/hle/service/nvnflinger/hardware_composer.h"
 #include "core/hle/service/nvnflinger/hwc_layer.h"
 #include "core/hle/service/nvnflinger/hwc_layer.h"
 #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
-#include "core/hle/service/vi/display/vi_display.h"
-#include "core/hle/service/vi/layer/vi_layer.h"
 
 
 namespace Service::Nvnflinger {
 namespace Service::Nvnflinger {
 
 
@@ -44,7 +42,7 @@ s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) {
 HardwareComposer::HardwareComposer() = default;
 HardwareComposer::HardwareComposer() = default;
 HardwareComposer::~HardwareComposer() = default;
 HardwareComposer::~HardwareComposer() = default;
 
 
-u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
+u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
                                     Nvidia::Devices::nvdisp_disp0& nvdisp) {
                                     Nvidia::Devices::nvdisp_disp0& nvdisp) {
     boost::container::small_vector<HwcLayer, 2> composition_stack;
     boost::container::small_vector<HwcLayer, 2> composition_stack;
 
 
@@ -56,12 +54,11 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
     bool has_acquired_buffer{};
     bool has_acquired_buffer{};
 
 
     // Acquire all necessary framebuffers.
     // Acquire all necessary framebuffers.
-    for (size_t i = 0; i < display.GetNumLayers(); i++) {
-        auto& layer = display.GetLayer(i);
-        auto layer_id = layer.GetLayerId();
+    for (auto& layer : display.stack.layers) {
+        auto consumer_id = layer.consumer_id;
 
 
         // Try to fetch the framebuffer (either new or stale).
         // Try to fetch the framebuffer (either new or stale).
-        const auto result = this->CacheFramebufferLocked(layer, layer_id);
+        const auto result = this->CacheFramebufferLocked(layer, consumer_id);
 
 
         // If we failed, skip this layer.
         // If we failed, skip this layer.
         if (result == CacheStatus::NoBufferAvailable) {
         if (result == CacheStatus::NoBufferAvailable) {
@@ -73,24 +70,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
             has_acquired_buffer = true;
             has_acquired_buffer = true;
         }
         }
 
 
-        const auto& buffer = m_framebuffers[layer_id];
+        const auto& buffer = m_framebuffers[consumer_id];
         const auto& item = buffer.item;
         const auto& item = buffer.item;
         const auto& igbp_buffer = *item.graphic_buffer;
         const auto& igbp_buffer = *item.graphic_buffer;
 
 
         // TODO: get proper Z-index from layer
         // TODO: get proper Z-index from layer
-        composition_stack.emplace_back(HwcLayer{
-            .buffer_handle = igbp_buffer.BufferId(),
-            .offset = igbp_buffer.Offset(),
-            .format = igbp_buffer.ExternalFormat(),
-            .width = igbp_buffer.Width(),
-            .height = igbp_buffer.Height(),
-            .stride = igbp_buffer.Stride(),
-            .z_index = 0,
-            .blending = layer.GetBlending(),
-            .transform = static_cast<android::BufferTransformFlags>(item.transform),
-            .crop_rect = item.crop,
-            .acquire_fence = item.fence,
-        });
+        if (layer.visible) {
+            composition_stack.emplace_back(HwcLayer{
+                .buffer_handle = igbp_buffer.BufferId(),
+                .offset = igbp_buffer.Offset(),
+                .format = igbp_buffer.ExternalFormat(),
+                .width = igbp_buffer.Width(),
+                .height = igbp_buffer.Height(),
+                .stride = igbp_buffer.Stride(),
+                .z_index = 0,
+                .blending = layer.blending,
+                .transform = static_cast<android::BufferTransformFlags>(item.transform),
+                .crop_rect = item.crop,
+                .acquire_fence = item.fence,
+            });
+        }
 
 
         // We need to compose again either before this frame is supposed to
         // We need to compose again either before this frame is supposed to
         // be released, or exactly on the vsync period it should be released.
         // be released, or exactly on the vsync period it should be released.
@@ -138,7 +137,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
         if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
         if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
             // TODO: support release fence
             // TODO: support release fence
             // This is needed to prevent screen tearing
             // This is needed to prevent screen tearing
-            layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
+            layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
             framebuffer.is_acquired = false;
             framebuffer.is_acquired = false;
         }
         }
     }
     }
@@ -146,26 +145,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
     return frame_advance;
     return frame_advance;
 }
 }
 
 
-void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
-    // Check if we are tracking a slot with this layer_id.
-    const auto it = m_framebuffers.find(layer_id);
+void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) {
+    // Check if we are tracking a slot with this consumer_id.
+    const auto it = m_framebuffers.find(consumer_id);
     if (it == m_framebuffers.end()) {
     if (it == m_framebuffers.end()) {
         return;
         return;
     }
     }
 
 
     // Try to release the buffer item.
     // Try to release the buffer item.
-    auto* const layer = display.FindLayer(layer_id);
+    auto* const layer = display.FindLayer(consumer_id);
     if (layer && it->second.is_acquired) {
     if (layer && it->second.is_acquired) {
-        layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence());
+        layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence());
     }
     }
 
 
     // Erase the slot.
     // Erase the slot.
     m_framebuffers.erase(it);
     m_framebuffers.erase(it);
 }
 }
 
 
-bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) {
+bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer) {
     // Attempt the update.
     // Attempt the update.
-    const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false);
+    const auto status = layer.buffer_item_consumer->AcquireBuffer(&framebuffer.item, {}, false);
     if (status != android::Status::NoError) {
     if (status != android::Status::NoError) {
         return false;
         return false;
     }
     }
@@ -178,10 +177,10 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer
     return true;
     return true;
 }
 }
 
 
-HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer,
-                                                                       LayerId layer_id) {
+HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(Layer& layer,
+                                                                       ConsumerId consumer_id) {
     // Check if this framebuffer is already present.
     // Check if this framebuffer is already present.
-    const auto it = m_framebuffers.find(layer_id);
+    const auto it = m_framebuffers.find(consumer_id);
     if (it != m_framebuffers.end()) {
     if (it != m_framebuffers.end()) {
         // If it's currently still acquired, we are done.
         // If it's currently still acquired, we are done.
         if (it->second.is_acquired) {
         if (it->second.is_acquired) {
@@ -203,7 +202,7 @@ HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer
 
 
     if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
     if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
         // Move the buffer item into a new slot.
         // Move the buffer item into a new slot.
-        m_framebuffers.emplace(layer_id, std::move(framebuffer));
+        m_framebuffers.emplace(consumer_id, std::move(framebuffer));
 
 
         // We succeeded.
         // We succeeded.
         return CacheStatus::BufferAcquired;
         return CacheStatus::BufferAcquired;

+ 7 - 13
src/core/hle/service/nvnflinger/hardware_composer.h

@@ -3,35 +3,29 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <memory>
 #include <boost/container/flat_map.hpp>
 #include <boost/container/flat_map.hpp>
 
 
 #include "core/hle/service/nvnflinger/buffer_item.h"
 #include "core/hle/service/nvnflinger/buffer_item.h"
+#include "core/hle/service/nvnflinger/display.h"
 
 
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 class nvdisp_disp0;
 class nvdisp_disp0;
 }
 }
 
 
-namespace Service::VI {
-class Display;
-class Layer;
-} // namespace Service::VI
-
 namespace Service::Nvnflinger {
 namespace Service::Nvnflinger {
 
 
-using LayerId = u64;
+using ConsumerId = s32;
 
 
 class HardwareComposer {
 class HardwareComposer {
 public:
 public:
     explicit HardwareComposer();
     explicit HardwareComposer();
     ~HardwareComposer();
     ~HardwareComposer();
 
 
-    u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
+    u32 ComposeLocked(f32* out_speed_scale, Display& display,
                       Nvidia::Devices::nvdisp_disp0& nvdisp);
                       Nvidia::Devices::nvdisp_disp0& nvdisp);
-    void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
+    void RemoveLayerLocked(Display& display, ConsumerId consumer_id);
 
 
 private:
 private:
-    // TODO: do we want to track frame number in vi instead?
     u64 m_frame_number{0};
     u64 m_frame_number{0};
 
 
 private:
 private:
@@ -49,11 +43,11 @@ private:
         CachedBufferReused,
         CachedBufferReused,
     };
     };
 
 
-    boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{};
+    boost::container::flat_map<ConsumerId, Framebuffer> m_framebuffers{};
 
 
 private:
 private:
-    bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer);
-    CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id);
+    bool TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer);
+    CacheStatus CacheFramebufferLocked(Layer& layer, ConsumerId consumer_id);
 };
 };
 
 
 } // namespace Service::Nvnflinger
 } // namespace Service::Nvnflinger

+ 15 - 5
src/core/hle/service/nvnflinger/hos_binder_driver.cpp

@@ -10,7 +10,7 @@ namespace Service::Nvnflinger {
 
 
 IHOSBinderDriver::IHOSBinderDriver(Core::System& system_,
 IHOSBinderDriver::IHOSBinderDriver(Core::System& system_,
                                    std::shared_ptr<HosBinderDriverServer> server,
                                    std::shared_ptr<HosBinderDriverServer> server,
-                                   std::shared_ptr<Nvnflinger> surface_flinger)
+                                   std::shared_ptr<SurfaceFlinger> surface_flinger)
     : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server),
     : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server),
       m_surface_flinger(surface_flinger) {
       m_surface_flinger(surface_flinger) {
     static const FunctionInfo functions[] = {
     static const FunctionInfo functions[] = {
@@ -24,13 +24,18 @@ IHOSBinderDriver::IHOSBinderDriver(Core::System& system_,
 
 
 IHOSBinderDriver::~IHOSBinderDriver() = default;
 IHOSBinderDriver::~IHOSBinderDriver() = default;
 
 
-Result IHOSBinderDriver::TransactParcel(s32 binder_id, android::TransactionId transaction_id,
+Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id,
                                         InBuffer<BufferAttr_HipcMapAlias> parcel_data,
                                         InBuffer<BufferAttr_HipcMapAlias> parcel_data,
                                         OutBuffer<BufferAttr_HipcMapAlias> parcel_reply,
                                         OutBuffer<BufferAttr_HipcMapAlias> parcel_reply,
                                         u32 flags) {
                                         u32 flags) {
     LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id,
     LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id,
               flags);
               flags);
-    m_server->TryGetProducer(binder_id)->Transact(transaction_id, flags, parcel_data, parcel_reply);
+
+    const auto binder = m_server->TryGetBinder(binder_id);
+    R_SUCCEED_IF(binder == nullptr);
+
+    binder->Transact(transaction_id, parcel_data, parcel_reply, flags);
+
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
@@ -42,11 +47,16 @@ Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) {
 Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id,
 Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id,
                                          OutCopyHandle<Kernel::KReadableEvent> out_handle) {
                                          OutCopyHandle<Kernel::KReadableEvent> out_handle) {
     LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id);
     LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id);
-    *out_handle = &m_server->TryGetProducer(binder_id)->GetNativeHandle();
+
+    const auto binder = m_server->TryGetBinder(binder_id);
+    R_UNLESS(binder != nullptr, ResultUnknown);
+
+    *out_handle = binder->GetNativeHandle(type_id);
+
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
-Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id,
+Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, u32 transaction_id,
                                             InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
                                             InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
                                             OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply,
                                             OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply,
                                             u32 flags) {
                                             u32 flags) {

+ 14 - 7
src/core/hle/service/nvnflinger/hos_binder_driver.h

@@ -2,38 +2,45 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 
 #include "core/hle/service/cmif_types.h"
 #include "core/hle/service/cmif_types.h"
-#include "core/hle/service/nvnflinger/binder.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
 
 
+namespace Kernel {
+class KReadableEvent;
+}
+
 namespace Service::Nvnflinger {
 namespace Service::Nvnflinger {
 
 
 class HosBinderDriverServer;
 class HosBinderDriverServer;
-class Nvnflinger;
+class SurfaceFlinger;
 
 
 class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
 class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
 public:
 public:
     explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server,
     explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server,
-                              std::shared_ptr<Nvnflinger> surface_flinger);
+                              std::shared_ptr<SurfaceFlinger> surface_flinger);
     ~IHOSBinderDriver() override;
     ~IHOSBinderDriver() override;
 
 
-    std::shared_ptr<Nvnflinger> GetSurfaceFlinger() {
+    std::shared_ptr<SurfaceFlinger> GetSurfaceFlinger() {
         return m_surface_flinger;
         return m_surface_flinger;
     }
     }
 
 
+    std::shared_ptr<HosBinderDriverServer> GetServer() {
+        return m_server;
+    }
+
 private:
 private:
-    Result TransactParcel(s32 binder_id, android::TransactionId transaction_id,
+    Result TransactParcel(s32 binder_id, u32 transaction_id,
                           InBuffer<BufferAttr_HipcMapAlias> parcel_data,
                           InBuffer<BufferAttr_HipcMapAlias> parcel_data,
                           OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags);
                           OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags);
     Result AdjustRefcount(s32 binder_id, s32 addval, s32 type);
     Result AdjustRefcount(s32 binder_id, s32 addval, s32 type);
     Result GetNativeHandle(s32 binder_id, u32 type_id,
     Result GetNativeHandle(s32 binder_id, u32 type_id,
                            OutCopyHandle<Kernel::KReadableEvent> out_handle);
                            OutCopyHandle<Kernel::KReadableEvent> out_handle);
-    Result TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id,
+    Result TransactParcelAuto(s32 binder_id, u32 transaction_id,
                               InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
                               InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
                               OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags);
                               OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags);
 
 
 private:
 private:
     const std::shared_ptr<HosBinderDriverServer> m_server;
     const std::shared_ptr<HosBinderDriverServer> m_server;
-    const std::shared_ptr<Nvnflinger> m_surface_flinger;
+    const std::shared_ptr<SurfaceFlinger> m_surface_flinger;
 };
 };
 
 
 } // namespace Service::Nvnflinger
 } // namespace Service::Nvnflinger

+ 13 - 9
src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp

@@ -8,26 +8,30 @@
 
 
 namespace Service::Nvnflinger {
 namespace Service::Nvnflinger {
 
 
-HosBinderDriverServer::HosBinderDriverServer(Core::System& system_)
-    : service_context(system_, "HosBinderDriverServer") {}
+HosBinderDriverServer::HosBinderDriverServer() = default;
+HosBinderDriverServer::~HosBinderDriverServer() = default;
 
 
-HosBinderDriverServer::~HosBinderDriverServer() {}
-
-u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) {
+s32 HosBinderDriverServer::RegisterBinder(std::shared_ptr<android::IBinder>&& binder) {
     std::scoped_lock lk{lock};
     std::scoped_lock lk{lock};
 
 
     last_id++;
     last_id++;
 
 
-    producers[last_id] = std::move(binder);
+    binders[last_id] = std::move(binder);
 
 
     return last_id;
     return last_id;
 }
 }
 
 
-android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) {
+void HosBinderDriverServer::UnregisterBinder(s32 binder_id) {
+    std::scoped_lock lk{lock};
+
+    binders.erase(binder_id);
+}
+
+std::shared_ptr<android::IBinder> HosBinderDriverServer::TryGetBinder(s32 id) const {
     std::scoped_lock lk{lock};
     std::scoped_lock lk{lock};
 
 
-    if (auto search = producers.find(id); search != producers.end()) {
-        return search->second.get();
+    if (auto search = binders.find(id); search != binders.end()) {
+        return search->second;
     }
     }
 
 
     return {};
     return {};

+ 7 - 9
src/core/hle/service/nvnflinger/hos_binder_driver_server.h

@@ -8,7 +8,6 @@
 #include <unordered_map>
 #include <unordered_map>
 
 
 #include "common/common_types.h"
 #include "common/common_types.h"
-#include "core/hle/service/kernel_helpers.h"
 #include "core/hle/service/nvnflinger/binder.h"
 #include "core/hle/service/nvnflinger/binder.h"
 
 
 namespace Core {
 namespace Core {
@@ -19,19 +18,18 @@ namespace Service::Nvnflinger {
 
 
 class HosBinderDriverServer final {
 class HosBinderDriverServer final {
 public:
 public:
-    explicit HosBinderDriverServer(Core::System& system_);
+    explicit HosBinderDriverServer();
     ~HosBinderDriverServer();
     ~HosBinderDriverServer();
 
 
-    u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder);
+    s32 RegisterBinder(std::shared_ptr<android::IBinder>&& binder);
+    void UnregisterBinder(s32 binder_id);
 
 
-    android::IBinder* TryGetProducer(u64 id);
+    std::shared_ptr<android::IBinder> TryGetBinder(s32 id) const;
 
 
 private:
 private:
-    KernelHelpers::ServiceContext service_context;
-
-    std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers;
-    std::mutex lock;
-    u64 last_id{};
+    std::unordered_map<s32, std::shared_ptr<android::IBinder>> binders;
+    mutable std::mutex lock;
+    s32 last_id{};
 };
 };
 
 
 } // namespace Service::Nvnflinger
 } // namespace Service::Nvnflinger

+ 3 - 302
src/core/hle/service/nvnflinger/nvnflinger.cpp

@@ -1,318 +1,19 @@
 // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-3.0-or-later
 // SPDX-License-Identifier: GPL-3.0-or-later
 
 
-#include "common/microprofile.h"
-#include "common/scope_exit.h"
-#include "common/settings.h"
 #include "core/core.h"
 #include "core/core.h"
-#include "core/core_timing.h"
-#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
-#include "core/hle/service/nvdrv/nvdrv.h"
-#include "core/hle/service/nvdrv/nvdrv_interface.h"
-#include "core/hle/service/nvnflinger/hardware_composer.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
 #include "core/hle/service/nvnflinger/nvnflinger.h"
 #include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/nvnflinger/surface_flinger.h"
 #include "core/hle/service/server_manager.h"
 #include "core/hle/service/server_manager.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hle/service/sm/sm.h"
-#include "core/hle/service/vi/display/vi_display.h"
-#include "core/hle/service/vi/layer/vi_layer.h"
-#include "core/hle/service/vi/vi_results.h"
 
 
 namespace Service::Nvnflinger {
 namespace Service::Nvnflinger {
 
 
-constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
-
-void Nvnflinger::SplitVSync(std::stop_token stop_token) {
-    system.RegisterHostThread();
-    std::string name = "VSyncThread";
-    MicroProfileOnThreadCreate(name.c_str());
-
-    // Cleanup
-    SCOPE_EXIT({ MicroProfileOnThreadExit(); });
-
-    Common::SetCurrentThreadName(name.c_str());
-    Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
-
-    while (!stop_token.stop_requested()) {
-        vsync_signal.Wait();
-
-        if (system.IsShuttingDown()) {
-            ShutdownLayers();
-            return;
-        }
-
-        const auto lock_guard = Lock();
-
-        if (!is_abandoned) {
-            Compose();
-        }
-    }
-}
-
-Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
-    : system(system_), service_context(system_, "nvnflinger"),
-      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>();
-
-    nvdrv = system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
-    disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
-
-    // Schedule the screen composition events
-    multi_composition_event = Core::Timing::CreateEvent(
-        "ScreenComposition",
-        [this](s64 time,
-               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
-            vsync_signal.Set();
-            return std::chrono::nanoseconds(GetNextTicks());
-        });
-
-    single_composition_event = Core::Timing::CreateEvent(
-        "ScreenComposition",
-        [this](s64 time,
-               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
-            const auto lock_guard = Lock();
-            Compose();
-
-            return std::chrono::nanoseconds(GetNextTicks());
-        });
-
-    if (system.IsMulticore()) {
-        system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, multi_composition_event);
-        vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
-    } else {
-        system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, single_composition_event);
-    }
-}
-
-Nvnflinger::~Nvnflinger() {
-    if (system.IsMulticore()) {
-        system.CoreTiming().UnscheduleEvent(multi_composition_event);
-        vsync_thread.request_stop();
-        vsync_signal.Set();
-    } else {
-        system.CoreTiming().UnscheduleEvent(single_composition_event);
-    }
-
-    ShutdownLayers();
-
-    if (nvdrv) {
-        nvdrv->Close(disp_fd);
-    }
-}
-
-void Nvnflinger::ShutdownLayers() {
-    // Abandon consumers.
-    const auto lock_guard = Lock();
-    for (auto& display : displays) {
-        display.Abandon();
-    }
-
-    is_abandoned = true;
-}
-
-std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) {
-    const auto lock_guard = Lock();
-
-    LOG_DEBUG(Service_Nvnflinger, "Opening \"{}\" display", name);
-
-    const auto itr =
-        std::find_if(displays.begin(), displays.end(),
-                     [&](const VI::Display& display) { return display.GetName() == name; });
-
-    if (itr == displays.end()) {
-        return std::nullopt;
-    }
-
-    return itr->GetID();
-}
-
-bool Nvnflinger::CloseDisplay(u64 display_id) {
-    const auto lock_guard = Lock();
-    auto* const display = FindDisplay(display_id);
-
-    if (display == nullptr) {
-        return false;
-    }
-
-    display->Reset();
-
-    return true;
-}
-
-std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) {
-    const auto lock_guard = Lock();
-    auto* const display = FindDisplay(display_id);
-
-    if (display == nullptr) {
-        return std::nullopt;
-    }
-
-    const u64 layer_id = next_layer_id++;
-    CreateLayerAtId(*display, layer_id, blending);
-    return layer_id;
-}
-
-void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) {
-    const auto buffer_id = next_buffer_queue_id++;
-    display.CreateLayer(layer_id, buffer_id, nvdrv->container);
-    display.FindLayer(layer_id)->SetBlending(blending);
-}
-
-bool Nvnflinger::OpenLayer(u64 layer_id) {
-    const auto lock_guard = Lock();
-
-    for (auto& display : displays) {
-        if (auto* layer = display.FindLayer(layer_id); layer) {
-            return layer->Open();
-        }
-    }
-
-    return false;
-}
-
-bool Nvnflinger::CloseLayer(u64 layer_id) {
-    const auto lock_guard = Lock();
-
-    for (auto& display : displays) {
-        if (auto* layer = display.FindLayer(layer_id); layer) {
-            return layer->Close();
-        }
-    }
-
-    return false;
-}
-
-void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) {
-    const auto lock_guard = Lock();
-
-    for (auto& display : displays) {
-        if (auto* layer = display.FindLayer(layer_id); layer) {
-            layer->SetVisibility(visible);
-        }
-    }
-}
-
-void Nvnflinger::DestroyLayer(u64 layer_id) {
-    const auto lock_guard = Lock();
-
-    for (auto& display : displays) {
-        display.DestroyLayer(layer_id);
-    }
-}
-
-std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
-    const auto lock_guard = Lock();
-    const auto* const layer = FindLayer(display_id, layer_id);
-
-    if (layer == nullptr) {
-        return std::nullopt;
-    }
-
-    return layer->GetBinderId();
-}
-
-Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) {
-    const auto lock_guard = Lock();
-    auto* const display = FindDisplay(display_id);
-
-    if (display == nullptr) {
-        return VI::ResultNotFound;
-    }
-
-    *out_vsync_event = display->GetVSyncEvent();
-    return ResultSuccess;
-}
-
-VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
-    const auto itr =
-        std::find_if(displays.begin(), displays.end(),
-                     [&](const VI::Display& display) { return display.GetID() == display_id; });
-
-    if (itr == displays.end()) {
-        return nullptr;
-    }
-
-    return &*itr;
-}
-
-const VI::Display* Nvnflinger::FindDisplay(u64 display_id) const {
-    const auto itr =
-        std::find_if(displays.begin(), displays.end(),
-                     [&](const VI::Display& display) { return display.GetID() == display_id; });
-
-    if (itr == displays.end()) {
-        return nullptr;
-    }
-
-    return &*itr;
-}
-
-VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) {
-    auto* const display = FindDisplay(display_id);
-
-    if (display == nullptr) {
-        return nullptr;
-    }
-
-    return display->FindLayer(layer_id);
-}
-
-void Nvnflinger::Compose() {
-    for (auto& display : displays) {
-        // Trigger vsync for this display at the end of drawing
-        SCOPE_EXIT({ display.SignalVSyncEvent(); });
-
-        // Don't do anything for displays without layers.
-        if (!display.HasLayers()) {
-            continue;
-        }
-
-        if (!system.IsPoweredOn()) {
-            return; // We are likely shutting down
-        }
-
-        auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
-        ASSERT(nvdisp);
-
-        swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
-    }
-}
-
-s64 Nvnflinger::GetNextTicks() const {
-    const auto& settings = Settings::values;
-    auto speed_scale = 1.f;
-    if (settings.use_multi_core.GetValue()) {
-        if (settings.use_speed_limit.GetValue()) {
-            // Scales the speed based on speed_limit setting on MC. SC is handled by
-            // SpeedLimiter::DoSpeedLimiting.
-            speed_scale = 100.f / settings.speed_limit.GetValue();
-        } else {
-            // Run at unlocked framerate.
-            speed_scale = 0.01f;
-        }
-    }
-
-    // Adjust by speed limit determined during composition.
-    speed_scale /= compose_speed_scale;
-
-    if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
-        // Run at intended presentation rate during video playback.
-        speed_scale = 1.f;
-    }
-
-    const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
-    return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
-}
-
 void LoopProcess(Core::System& system) {
 void LoopProcess(Core::System& system) {
-    const auto binder_server = std::make_shared<HosBinderDriverServer>(system);
-    const auto surface_flinger = std::make_shared<Nvnflinger>(system, *binder_server);
+    const auto binder_server = std::make_shared<HosBinderDriverServer>();
+    const auto surface_flinger = std::make_shared<SurfaceFlinger>(system, *binder_server);
 
 
     auto server_manager = std::make_unique<ServerManager>(system);
     auto server_manager = std::make_unique<ServerManager>(system);
     server_manager->RegisterNamedService(
     server_manager->RegisterNamedService(

+ 3 - 149
src/core/hle/service/nvnflinger/nvnflinger.h

@@ -3,158 +3,12 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <list>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <thread>
-
-#include "common/common_types.h"
-#include "common/polyfill_thread.h"
-#include "common/thread.h"
-#include "core/hle/result.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/nvnflinger/hwc_layer.h"
-
-namespace Common {
-class Event;
-} // namespace Common
-
-namespace Core::Timing {
-class CoreTiming;
-struct EventType;
-} // namespace Core::Timing
-
-namespace Kernel {
-class KReadableEvent;
-} // namespace Kernel
-
-namespace Service::Nvidia {
-class Module;
-} // namespace Service::Nvidia
-
-namespace Service::VI {
-class Display;
-class FbshareBufferManager;
-class Layer;
-} // namespace Service::VI
-
-namespace Service::android {
-class BufferQueueCore;
-class BufferQueueProducer;
-} // namespace Service::android
+namespace Core {
+class System;
+}
 
 
 namespace Service::Nvnflinger {
 namespace Service::Nvnflinger {
 
 
-class HardwareComposer;
-class HosBinderDriverServer;
-
-class Nvnflinger final {
-public:
-    explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
-    ~Nvnflinger();
-
-    void ShutdownLayers();
-
-    /// Opens the specified display and returns the ID.
-    ///
-    /// If an invalid display name is provided, then an empty optional is returned.
-    [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name);
-
-    /// Closes the specified display by its ID.
-    ///
-    /// Returns false if an invalid display ID is provided.
-    [[nodiscard]] bool CloseDisplay(u64 display_id);
-
-    /// Creates a layer on the specified display and returns the layer ID.
-    ///
-    /// If an invalid display ID is specified, then an empty optional is returned.
-    [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id,
-                                                 LayerBlending blending = LayerBlending::None);
-
-    /// Opens a layer on all displays for the given layer ID.
-    bool OpenLayer(u64 layer_id);
-
-    /// Closes a layer on all displays for the given layer ID.
-    bool CloseLayer(u64 layer_id);
-
-    /// Makes a layer visible on all displays for the given layer ID.
-    void SetLayerVisibility(u64 layer_id, bool visible);
-
-    /// Destroys the given layer ID.
-    void DestroyLayer(u64 layer_id);
-
-    /// Finds the buffer queue ID of the specified layer in the specified display.
-    ///
-    /// If an invalid display ID or layer ID is provided, then an empty optional is returned.
-    [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id);
-
-    /// Gets the vsync event for the specified display.
-    ///
-    /// If an invalid display ID is provided, then VI::ResultNotFound is returned.
-    /// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned.
-    [[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id);
-
-    /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
-    /// finished.
-    void Compose();
-
-    [[nodiscard]] s64 GetNextTicks() const;
-
-private:
-    friend class VI::FbshareBufferManager;
-
-    [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
-        return std::unique_lock{*guard};
-    }
-
-    /// Finds the display identified by the specified ID.
-    [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
-
-    /// Finds the display identified by the specified ID.
-    [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
-
-    /// Finds the layer identified by the specified ID in the desired display.
-    [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
-
-    /// Creates a layer with the specified layer ID in the desired display.
-    void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending);
-
-    void SplitVSync(std::stop_token stop_token);
-
-    std::shared_ptr<Nvidia::Module> nvdrv;
-    s32 disp_fd;
-
-    std::list<VI::Display> displays;
-
-    /// Id to use for the next layer that is created, this counter is shared among all displays.
-    u64 next_layer_id = 1;
-    /// Id to use for the next buffer queue that is created, this counter is shared among all
-    /// layers.
-    u32 next_buffer_queue_id = 1;
-
-    s32 swap_interval = 1;
-    f32 compose_speed_scale = 1.0f;
-
-    bool is_abandoned = false;
-
-    /// Event that handles screen composition.
-    std::shared_ptr<Core::Timing::EventType> multi_composition_event;
-    std::shared_ptr<Core::Timing::EventType> single_composition_event;
-
-    std::shared_ptr<std::mutex> guard;
-
-    Core::System& system;
-
-    Common::Event vsync_signal;
-
-    std::jthread vsync_thread;
-
-    KernelHelpers::ServiceContext service_context;
-
-    HosBinderDriverServer& hos_binder_driver_server;
-};
-
 void LoopProcess(Core::System& system);
 void LoopProcess(Core::System& system);
 
 
 } // namespace Service::Nvnflinger
 } // namespace Service::Nvnflinger

+ 123 - 0
src/core/hle/service/nvnflinger/surface_flinger.cpp

@@ -0,0 +1,123 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
+#include "core/hle/service/nvdrv/nvdrv_interface.h"
+#include "core/hle/service/nvnflinger/display.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
+#include "core/hle/service/nvnflinger/surface_flinger.h"
+#include "core/hle/service/sm/sm.h"
+
+#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
+
+namespace Service::Nvnflinger {
+
+SurfaceFlinger::SurfaceFlinger(Core::System& system, HosBinderDriverServer& server)
+    : m_system(system), m_server(server), m_context(m_system, "SurfaceFlinger") {
+    nvdrv = m_system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
+    disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
+}
+
+SurfaceFlinger::~SurfaceFlinger() {
+    nvdrv->Close(disp_fd);
+}
+
+void SurfaceFlinger::AddDisplay(u64 display_id) {
+    m_displays.emplace_back(display_id);
+}
+
+void SurfaceFlinger::RemoveDisplay(u64 display_id) {
+    std::erase_if(m_displays, [&](auto& display) { return display.id == display_id; });
+}
+
+void SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
+                                    u64 display_id) {
+    auto* const display = this->FindDisplay(display_id);
+    if (!display) {
+        return;
+    }
+
+    *out_swap_interval =
+        m_composer.ComposeLocked(out_compose_speed_scale, *display,
+                                 *nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd));
+}
+
+void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
+    auto* const display = this->FindDisplay(display_id);
+    auto binder = std::static_pointer_cast<android::BufferQueueConsumer>(
+        m_server.TryGetBinder(consumer_binder_id));
+
+    if (!display || !binder) {
+        return;
+    }
+
+    auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder));
+    buffer_item_consumer->Connect(false);
+
+    display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id);
+}
+
+void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) {
+    auto* const display = this->FindDisplay(display_id);
+    if (!display) {
+        return;
+    }
+
+    m_composer.RemoveLayerLocked(*display, consumer_binder_id);
+    std::erase_if(display->stack.layers,
+                  [&](auto& layer) { return layer.consumer_id == consumer_binder_id; });
+}
+
+void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) {
+    if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
+        layer->visible = visible;
+        return;
+    }
+}
+
+void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) {
+    if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
+        layer->blending = blending;
+        return;
+    }
+}
+
+Display* SurfaceFlinger::FindDisplay(u64 display_id) {
+    for (auto& display : m_displays) {
+        if (display.id == display_id) {
+            return &display;
+        }
+    }
+
+    return nullptr;
+}
+
+Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
+    for (auto& display : m_displays) {
+        if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) {
+            return layer;
+        }
+    }
+
+    return nullptr;
+}
+
+void SurfaceFlinger::CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id) {
+    auto& nvmap = nvdrv->GetContainer().GetNvMapFile();
+    auto core = std::make_shared<android::BufferQueueCore>();
+    auto producer = std::make_shared<android::BufferQueueProducer>(m_context, core, nvmap);
+    auto consumer = std::make_shared<android::BufferQueueConsumer>(core);
+
+    *out_consumer_binder_id = m_server.RegisterBinder(std::move(consumer));
+    *out_producer_binder_id = m_server.RegisterBinder(std::move(producer));
+}
+
+void SurfaceFlinger::DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id) {
+    m_server.UnregisterBinder(producer_binder_id);
+    m_server.UnregisterBinder(consumer_binder_id);
+}
+
+} // namespace Service::Nvnflinger

+ 65 - 0
src/core/hle/service/nvnflinger/surface_flinger.h

@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <vector>
+
+#include "common/common_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nvnflinger/hardware_composer.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::Nvidia {
+class Module;
+}
+
+// TODO: ISurfaceComposer
+// TODO: ISurfaceComposerClient
+
+namespace Service::Nvnflinger {
+
+struct Display;
+class HosBinderDriverServer;
+enum class LayerBlending : u32;
+struct Layer;
+
+class SurfaceFlinger {
+public:
+    explicit SurfaceFlinger(Core::System& system, HosBinderDriverServer& server);
+    ~SurfaceFlinger();
+
+    void AddDisplay(u64 display_id);
+    void RemoveDisplay(u64 display_id);
+    void ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
+
+    void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id);
+    void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id);
+
+    void SetLayerVisibility(s32 consumer_binder_id, bool visible);
+    void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
+
+private:
+    Display* FindDisplay(u64 display_id);
+    Layer* FindLayer(s32 consumer_binder_id);
+
+public:
+    // TODO: these don't belong here
+    void CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id);
+    void DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id);
+
+private:
+    Core::System& m_system;
+    HosBinderDriverServer& m_server;
+    KernelHelpers::ServiceContext m_context;
+
+    std::vector<Display> m_displays;
+    std::shared_ptr<Nvidia::Module> nvdrv;
+    s32 disp_fd;
+    HardwareComposer m_composer;
+};
+
+} // namespace Service::Nvnflinger

+ 0 - 126
src/core/hle/service/service.cpp

@@ -7,67 +7,10 @@
 #include "common/settings.h"
 #include "common/settings.h"
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/ipc.h"
 #include "core/hle/ipc.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/k_server_port.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/kernel.h"
-#include "core/hle/service/acc/acc.h"
-#include "core/hle/service/am/am.h"
-#include "core/hle/service/aoc/aoc_u.h"
-#include "core/hle/service/apm/apm.h"
-#include "core/hle/service/audio/audio.h"
-#include "core/hle/service/bcat/bcat.h"
-#include "core/hle/service/bpc/bpc.h"
-#include "core/hle/service/btdrv/btdrv.h"
-#include "core/hle/service/btm/btm.h"
-#include "core/hle/service/caps/caps.h"
-#include "core/hle/service/erpt/erpt.h"
-#include "core/hle/service/es/es.h"
-#include "core/hle/service/eupld/eupld.h"
-#include "core/hle/service/fatal/fatal.h"
-#include "core/hle/service/fgm/fgm.h"
-#include "core/hle/service/filesystem/filesystem.h"
-#include "core/hle/service/friend/friend.h"
-#include "core/hle/service/glue/glue.h"
-#include "core/hle/service/grc/grc.h"
-#include "core/hle/service/hid/hid.h"
 #include "core/hle/service/ipc_helpers.h"
 #include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/jit/jit.h"
-#include "core/hle/service/lbl/lbl.h"
-#include "core/hle/service/ldn/ldn.h"
-#include "core/hle/service/ldr/ldr.h"
-#include "core/hle/service/lm/lm.h"
-#include "core/hle/service/mig/mig.h"
-#include "core/hle/service/mii/mii.h"
-#include "core/hle/service/mm/mm_u.h"
-#include "core/hle/service/mnpp/mnpp_app.h"
-#include "core/hle/service/ncm/ncm.h"
-#include "core/hle/service/nfc/nfc.h"
-#include "core/hle/service/nfp/nfp.h"
-#include "core/hle/service/ngc/ngc.h"
-#include "core/hle/service/nifm/nifm.h"
-#include "core/hle/service/nim/nim.h"
-#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/nvnflinger/nvnflinger.h"
-#include "core/hle/service/olsc/olsc.h"
-#include "core/hle/service/omm/omm.h"
-#include "core/hle/service/pcie/pcie.h"
-#include "core/hle/service/pctl/pctl_module.h"
-#include "core/hle/service/pcv/pcv.h"
-#include "core/hle/service/pm/pm.h"
-#include "core/hle/service/prepo/prepo.h"
-#include "core/hle/service/psc/psc.h"
-#include "core/hle/service/ptm/ptm.h"
-#include "core/hle/service/ro/ro.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
-#include "core/hle/service/set/settings.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hle/service/sm/sm.h"
-#include "core/hle/service/sockets/sockets.h"
-#include "core/hle/service/spl/spl_module.h"
-#include "core/hle/service/ssl/ssl.h"
-#include "core/hle/service/usb/usb.h"
-#include "core/hle/service/vi/vi.h"
 #include "core/reporter.h"
 #include "core/reporter.h"
 
 
 namespace Service {
 namespace Service {
@@ -208,73 +151,4 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
     return result;
     return result;
 }
 }
 
 
-/// Initialize Services
-Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
-    auto& kernel = system.Kernel();
-
-    system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
-
-    // clang-format off
-    kernel.RunOnHostCoreProcess("audio",      [&] { Audio::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("FS",         [&] { FileSystem::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("jit",        [&] { JIT::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("ldn",        [&] { LDN::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("Loader",     [&] { LDR::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("bsdsocket",  [&] { Sockets::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("vi",         [&] { VI::LoopProcess(system); }).detach();
-    kernel.RunOnHostCoreProcess("nvnflinger", [&] { Nvnflinger::LoopProcess(system); }).detach();
-
-    kernel.RunOnGuestCoreProcess("sm",         [&] { SM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("account",    [&] { Account::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("am",         [&] { AM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("aoc",        [&] { AOC::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("apm",        [&] { APM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("bcat",       [&] { BCAT::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("bpc",        [&] { BPC::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("btdrv",      [&] { BtDrv::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("btm",        [&] { BTM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("capsrv",     [&] { Capture::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("erpt",       [&] { ERPT::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("es",         [&] { ES::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("eupld",      [&] { EUPLD::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("fatal",      [&] { Fatal::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("fgm",        [&] { FGM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("friends",    [&] { Friend::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("settings",   [&] { Set::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("psc",        [&] { PSC::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("glue",       [&] { Glue::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("grc",        [&] { GRC::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("hid",        [&] { HID::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("lbl",        [&] { LBL::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("mig",        [&] { Migration::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("mii",        [&] { Mii::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("mm",         [&] { MM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("mnpp",       [&] { MNPP::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("NCM",        [&] { NCM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("nfc",        [&] { NFC::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("nfp",        [&] { NFP::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("ngc",        [&] { NGC::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("nifm",       [&] { NIFM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("nim",        [&] { NIM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("npns",       [&] { NPNS::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("ns",         [&] { NS::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("olsc",       [&] { OLSC::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("omm",        [&] { OMM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("pcie",       [&] { PCIe::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("pctl",       [&] { PCTL::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("pcv",        [&] { PCV::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("prepo",      [&] { PlayReport::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("ptm",        [&] { PTM::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("ro",         [&] { RO::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("spl",        [&] { SPL::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("ssl",        [&] { SSL::LoopProcess(system); });
-    kernel.RunOnGuestCoreProcess("usb",        [&] { USB::LoopProcess(system); });
-    // clang-format on
-}
-
-Services::~Services() = default;
-
 } // namespace Service
 } // namespace Service

+ 0 - 10
src/core/hle/service/service.h

@@ -231,14 +231,4 @@ private:
     }
     }
 };
 };
 
 
-/**
- * The purpose of this class is to own any objects that need to be shared across the other service
- * implementations. Will be torn down when the global system instance is shutdown.
- */
-class Services final {
-public:
-    explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
-    ~Services();
-};
-
 } // namespace Service
 } // namespace Service

+ 136 - 0
src/core/hle/service/services.cpp

@@ -0,0 +1,136 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/services.h"
+
+#include "core/hle/service/acc/acc.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/aoc/aoc_u.h"
+#include "core/hle/service/apm/apm.h"
+#include "core/hle/service/audio/audio.h"
+#include "core/hle/service/bcat/bcat.h"
+#include "core/hle/service/bpc/bpc.h"
+#include "core/hle/service/btdrv/btdrv.h"
+#include "core/hle/service/btm/btm.h"
+#include "core/hle/service/caps/caps.h"
+#include "core/hle/service/erpt/erpt.h"
+#include "core/hle/service/es/es.h"
+#include "core/hle/service/eupld/eupld.h"
+#include "core/hle/service/fatal/fatal.h"
+#include "core/hle/service/fgm/fgm.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/friend/friend.h"
+#include "core/hle/service/glue/glue.h"
+#include "core/hle/service/grc/grc.h"
+#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/jit/jit.h"
+#include "core/hle/service/lbl/lbl.h"
+#include "core/hle/service/ldn/ldn.h"
+#include "core/hle/service/ldr/ldr.h"
+#include "core/hle/service/lm/lm.h"
+#include "core/hle/service/mig/mig.h"
+#include "core/hle/service/mii/mii.h"
+#include "core/hle/service/mm/mm_u.h"
+#include "core/hle/service/mnpp/mnpp_app.h"
+#include "core/hle/service/ncm/ncm.h"
+#include "core/hle/service/nfc/nfc.h"
+#include "core/hle/service/nfp/nfp.h"
+#include "core/hle/service/ngc/ngc.h"
+#include "core/hle/service/nifm/nifm.h"
+#include "core/hle/service/nim/nim.h"
+#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/nvnflinger/nvnflinger.h"
+#include "core/hle/service/olsc/olsc.h"
+#include "core/hle/service/omm/omm.h"
+#include "core/hle/service/pcie/pcie.h"
+#include "core/hle/service/pctl/pctl_module.h"
+#include "core/hle/service/pcv/pcv.h"
+#include "core/hle/service/pm/pm.h"
+#include "core/hle/service/prepo/prepo.h"
+#include "core/hle/service/psc/psc.h"
+#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ro/ro.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/set/settings.h"
+#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/sockets/sockets.h"
+#include "core/hle/service/spl/spl_module.h"
+#include "core/hle/service/ssl/ssl.h"
+#include "core/hle/service/usb/usb.h"
+#include "core/hle/service/vi/vi.h"
+
+namespace Service {
+
+Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
+                   std::stop_token token) {
+    auto& kernel = system.Kernel();
+
+    system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
+
+    // clang-format off
+    kernel.RunOnHostCoreProcess("audio",      [&] { Audio::LoopProcess(system); }).detach();
+    kernel.RunOnHostCoreProcess("FS",         [&] { FileSystem::LoopProcess(system); }).detach();
+    kernel.RunOnHostCoreProcess("jit",        [&] { JIT::LoopProcess(system); }).detach();
+    kernel.RunOnHostCoreProcess("ldn",        [&] { LDN::LoopProcess(system); }).detach();
+    kernel.RunOnHostCoreProcess("Loader",     [&] { LDR::LoopProcess(system); }).detach();
+    kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(system); }).detach();
+    kernel.RunOnHostCoreProcess("bsdsocket",  [&] { Sockets::LoopProcess(system); }).detach();
+    kernel.RunOnHostCoreProcess("vi",         [&, token] { VI::LoopProcess(system, token); }).detach();
+
+    kernel.RunOnGuestCoreProcess("sm",         [&] { SM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("account",    [&] { Account::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("am",         [&] { AM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("aoc",        [&] { AOC::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("apm",        [&] { APM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("bcat",       [&] { BCAT::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("bpc",        [&] { BPC::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("btdrv",      [&] { BtDrv::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("btm",        [&] { BTM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("capsrv",     [&] { Capture::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("erpt",       [&] { ERPT::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("es",         [&] { ES::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("eupld",      [&] { EUPLD::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("fatal",      [&] { Fatal::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("fgm",        [&] { FGM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("friends",    [&] { Friend::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("settings",   [&] { Set::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("psc",        [&] { PSC::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("glue",       [&] { Glue::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("grc",        [&] { GRC::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("hid",        [&] { HID::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("lbl",        [&] { LBL::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("mig",        [&] { Migration::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("mii",        [&] { Mii::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("mm",         [&] { MM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("mnpp",       [&] { MNPP::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("nvnflinger", [&] { Nvnflinger::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("NCM",        [&] { NCM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("nfc",        [&] { NFC::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("nfp",        [&] { NFP::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("ngc",        [&] { NGC::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("nifm",       [&] { NIFM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("nim",        [&] { NIM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("npns",       [&] { NPNS::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("ns",         [&] { NS::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("olsc",       [&] { OLSC::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("omm",        [&] { OMM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("pcie",       [&] { PCIe::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("pctl",       [&] { PCTL::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("pcv",        [&] { PCV::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("prepo",      [&] { PlayReport::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("ptm",        [&] { PTM::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("ro",         [&] { RO::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("spl",        [&] { SPL::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("ssl",        [&] { SSL::LoopProcess(system); });
+    kernel.RunOnGuestCoreProcess("usb",        [&] { USB::LoopProcess(system); });
+    // clang-format on
+}
+
+Services::~Services() = default;
+
+} // namespace Service

+ 22 - 0
src/core/hle/service/services.h

@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/polyfill_thread.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service {
+
+/**
+ * The purpose of this class is to own any objects that need to be shared across the other service
+ * implementations. Will be torn down when the global system instance is shutdown.
+ */
+class Services final {
+public:
+    explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
+                      std::stop_token token);
+    ~Services();
+};
+
+} // namespace Service

+ 49 - 69
src/core/hle/service/vi/application_display_service.cpp

@@ -3,23 +3,20 @@
 
 
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver.h"
-#include "core/hle/service/nvnflinger/nvnflinger.h"
 #include "core/hle/service/nvnflinger/parcel.h"
 #include "core/hle/service/nvnflinger/parcel.h"
+#include "core/hle/service/os/event.h"
 #include "core/hle/service/vi/application_display_service.h"
 #include "core/hle/service/vi/application_display_service.h"
+#include "core/hle/service/vi/container.h"
 #include "core/hle/service/vi/manager_display_service.h"
 #include "core/hle/service/vi/manager_display_service.h"
 #include "core/hle/service/vi/system_display_service.h"
 #include "core/hle/service/vi/system_display_service.h"
 #include "core/hle/service/vi/vi_results.h"
 #include "core/hle/service/vi/vi_results.h"
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-IApplicationDisplayService::IApplicationDisplayService(
-    Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-    std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
+IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
+                                                       std::shared_ptr<Container> container)
     : ServiceFramework{system_, "IApplicationDisplayService"},
     : ServiceFramework{system_, "IApplicationDisplayService"},
-      m_binder_service{std::move(binder_service)},
-      m_surface_flinger{m_binder_service->GetSurfaceFlinger()},
-      m_shared_buffer_manager{std::move(shared_buffer_manager)} {
-
+      m_container{std::move(container)}, m_context{system, "IApplicationDisplayService"} {
     // clang-format off
     // clang-format off
     static const FunctionInfo functions[] = {
     static const FunctionInfo functions[] = {
         {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"},
         {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"},
@@ -50,39 +47,41 @@ IApplicationDisplayService::IApplicationDisplayService(
 }
 }
 
 
 IApplicationDisplayService::~IApplicationDisplayService() {
 IApplicationDisplayService::~IApplicationDisplayService() {
+    for (auto& [display_id, event] : m_display_vsync_events) {
+        m_container->UnlinkVsyncEvent(display_id, &event);
+    }
+    for (const auto layer_id : m_open_layer_ids) {
+        m_container->CloseLayer(layer_id);
+    }
     for (const auto layer_id : m_stray_layer_ids) {
     for (const auto layer_id : m_stray_layer_ids) {
-        m_surface_flinger->DestroyLayer(layer_id);
+        m_container->DestroyStrayLayer(layer_id);
     }
     }
 }
 }
 
 
 Result IApplicationDisplayService::GetRelayService(
 Result IApplicationDisplayService::GetRelayService(
     Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) {
     Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) {
     LOG_WARNING(Service_VI, "(STUBBED) called");
     LOG_WARNING(Service_VI, "(STUBBED) called");
-    *out_relay_service = m_binder_service;
-    R_SUCCEED();
+    R_RETURN(m_container->GetBinderDriver(out_relay_service));
 }
 }
 
 
 Result IApplicationDisplayService::GetSystemDisplayService(
 Result IApplicationDisplayService::GetSystemDisplayService(
     Out<SharedPointer<ISystemDisplayService>> out_system_display_service) {
     Out<SharedPointer<ISystemDisplayService>> out_system_display_service) {
     LOG_WARNING(Service_VI, "(STUBBED) called");
     LOG_WARNING(Service_VI, "(STUBBED) called");
-    *out_system_display_service =
-        std::make_shared<ISystemDisplayService>(system, m_surface_flinger, m_shared_buffer_manager);
+    *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_container);
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
 Result IApplicationDisplayService::GetManagerDisplayService(
 Result IApplicationDisplayService::GetManagerDisplayService(
     Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) {
     Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) {
     LOG_WARNING(Service_VI, "(STUBBED) called");
     LOG_WARNING(Service_VI, "(STUBBED) called");
-    *out_manager_display_service =
-        std::make_shared<IManagerDisplayService>(system, m_surface_flinger);
+    *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_container);
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
 Result IApplicationDisplayService::GetIndirectDisplayTransactionService(
 Result IApplicationDisplayService::GetIndirectDisplayTransactionService(
     Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service) {
     Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service) {
     LOG_WARNING(Service_VI, "(STUBBED) called");
     LOG_WARNING(Service_VI, "(STUBBED) called");
-    *out_indirect_display_transaction_service = m_binder_service;
-    R_SUCCEED();
+    R_RETURN(m_container->GetBinderDriver(out_indirect_display_transaction_service));
 }
 }
 
 
 Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) {
 Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) {
@@ -92,14 +91,7 @@ Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayN
     ASSERT_MSG(strcmp(display_name.data(), "Default") == 0,
     ASSERT_MSG(strcmp(display_name.data(), "Default") == 0,
                "Non-default displays aren't supported yet");
                "Non-default displays aren't supported yet");
 
 
-    const auto display_id = m_surface_flinger->OpenDisplay(display_name.data());
-    if (!display_id) {
-        LOG_ERROR(Service_VI, "Display not found! display_name={}", display_name.data());
-        R_THROW(VI::ResultNotFound);
-    }
-
-    *out_display_id = *display_id;
-    R_SUCCEED();
+    R_RETURN(m_container->OpenDisplay(out_display_id, display_name));
 }
 }
 
 
 Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
 Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
@@ -109,8 +101,7 @@ Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
 
 
 Result IApplicationDisplayService::CloseDisplay(u64 display_id) {
 Result IApplicationDisplayService::CloseDisplay(u64 display_id) {
     LOG_DEBUG(Service_VI, "called");
     LOG_DEBUG(Service_VI, "called");
-    R_SUCCEED_IF(m_surface_flinger->CloseDisplay(display_id));
-    R_THROW(ResultUnknown);
+    R_RETURN(m_container->CloseDisplay(display_id));
 }
 }
 
 
 Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) {
 Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) {
@@ -171,25 +162,19 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
 
 
     LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid);
     LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid);
 
 
-    const auto display_id = m_surface_flinger->OpenDisplay(display_name.data());
-    if (!display_id) {
-        LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
-        R_THROW(VI::ResultNotFound);
-    }
+    u64 display_id;
+    R_TRY(m_container->OpenDisplay(&display_id, display_name));
 
 
-    const auto buffer_queue_id = m_surface_flinger->FindBufferQueueId(*display_id, layer_id);
-    if (!buffer_queue_id) {
-        LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
-        R_THROW(VI::ResultNotFound);
-    }
+    s32 producer_binder_id;
+    R_TRY(m_container->OpenLayer(&producer_binder_id, layer_id, aruid.pid));
 
 
-    if (!m_surface_flinger->OpenLayer(layer_id)) {
-        LOG_WARNING(Service_VI, "Tried to open layer which was already open");
-        R_THROW(VI::ResultOperationFailed);
+    {
+        std::scoped_lock lk{m_lock};
+        m_open_layer_ids.insert(layer_id);
     }
     }
 
 
     android::OutputParcel parcel;
     android::OutputParcel parcel;
-    parcel.WriteInterface(NativeWindow{*buffer_queue_id});
+    parcel.WriteInterface(NativeWindow{producer_binder_id});
 
 
     const auto buffer = parcel.Serialize();
     const auto buffer = parcel.Serialize();
     std::memcpy(out_native_window.data(), buffer.data(),
     std::memcpy(out_native_window.data(), buffer.data(),
@@ -202,12 +187,13 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
 Result IApplicationDisplayService::CloseLayer(u64 layer_id) {
 Result IApplicationDisplayService::CloseLayer(u64 layer_id) {
     LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
     LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
 
 
-    if (!m_surface_flinger->CloseLayer(layer_id)) {
-        LOG_WARNING(Service_VI, "Tried to close layer which was not open");
-        R_THROW(VI::ResultOperationFailed);
+    {
+        std::scoped_lock lk{m_lock};
+        R_UNLESS(m_open_layer_ids.contains(layer_id), VI::ResultNotFound);
+        m_open_layer_ids.erase(layer_id);
     }
     }
 
 
-    R_SUCCEED();
+    R_RETURN(m_container->CloseLayer(layer_id));
 }
 }
 
 
 Result IApplicationDisplayService::CreateStrayLayer(
 Result IApplicationDisplayService::CreateStrayLayer(
@@ -215,27 +201,19 @@ Result IApplicationDisplayService::CreateStrayLayer(
     u32 flags, u64 display_id) {
     u32 flags, u64 display_id) {
     LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id);
     LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id);
 
 
-    const auto layer_id = m_surface_flinger->CreateLayer(display_id);
-    if (!layer_id) {
-        LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
-        R_THROW(VI::ResultNotFound);
-    }
+    s32 producer_binder_id;
+    R_TRY(m_container->CreateStrayLayer(&producer_binder_id, out_layer_id, display_id));
 
 
-    m_stray_layer_ids.push_back(*layer_id);
-    const auto buffer_queue_id = m_surface_flinger->FindBufferQueueId(display_id, *layer_id);
-    if (!buffer_queue_id) {
-        LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
-        R_THROW(VI::ResultNotFound);
-    }
+    std::scoped_lock lk{m_lock};
+    m_stray_layer_ids.insert(*out_layer_id);
 
 
     android::OutputParcel parcel;
     android::OutputParcel parcel;
-    parcel.WriteInterface(NativeWindow{*buffer_queue_id});
+    parcel.WriteInterface(NativeWindow{producer_binder_id});
 
 
     const auto buffer = parcel.Serialize();
     const auto buffer = parcel.Serialize();
     std::memcpy(out_native_window.data(), buffer.data(),
     std::memcpy(out_native_window.data(), buffer.data(),
                 std::min(out_native_window.size(), buffer.size()));
                 std::min(out_native_window.size(), buffer.size()));
 
 
-    *out_layer_id = *layer_id;
     *out_size = buffer.size();
     *out_size = buffer.size();
 
 
     R_SUCCEED();
     R_SUCCEED();
@@ -243,25 +221,27 @@ Result IApplicationDisplayService::CreateStrayLayer(
 
 
 Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) {
 Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) {
     LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
     LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
-    m_surface_flinger->DestroyLayer(layer_id);
-    R_SUCCEED();
+
+    {
+        std::scoped_lock lk{m_lock};
+        R_UNLESS(m_stray_layer_ids.contains(layer_id), VI::ResultNotFound);
+        m_stray_layer_ids.erase(layer_id);
+    }
+
+    R_RETURN(m_container->DestroyStrayLayer(layer_id));
 }
 }
 
 
 Result IApplicationDisplayService::GetDisplayVsyncEvent(
 Result IApplicationDisplayService::GetDisplayVsyncEvent(
     OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) {
     OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) {
     LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
     LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
 
 
-    const auto result = m_surface_flinger->FindVsyncEvent(out_vsync_event, display_id);
-    if (result != ResultSuccess) {
-        if (result == ResultNotFound) {
-            LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
-        }
+    std::scoped_lock lk{m_lock};
 
 
-        R_THROW(result);
-    }
+    auto [it, created] = m_display_vsync_events.emplace(display_id, m_context);
+    R_UNLESS(created, VI::ResultPermissionDenied);
 
 
-    R_UNLESS(!m_vsync_event_fetched, VI::ResultPermissionDenied);
-    m_vsync_event_fetched = true;
+    m_container->LinkVsyncEvent(display_id, &it->second);
+    *out_vsync_event = it->second.GetHandle();
 
 
     R_SUCCEED();
     R_SUCCEED();
 }
 }

+ 18 - 13
src/core/hle/service/vi/application_display_service.h

@@ -1,7 +1,12 @@
 // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 
+#include <map>
+#include <set>
+
 #include "core/hle/service/cmif_types.h"
 #include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/os/event.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/vi/vi_types.h"
 #include "core/hle/service/vi/vi_types.h"
 
 
@@ -10,28 +15,25 @@ class KReadableEvent;
 }
 }
 
 
 namespace Service::Nvnflinger {
 namespace Service::Nvnflinger {
-class Nvnflinger;
 class IHOSBinderDriver;
 class IHOSBinderDriver;
-} // namespace Service::Nvnflinger
+}
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-class FbshareBufferManager;
+class Container;
 class IManagerDisplayService;
 class IManagerDisplayService;
 class ISystemDisplayService;
 class ISystemDisplayService;
 
 
 class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
 class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
 public:
 public:
-    IApplicationDisplayService(Core::System& system_,
-                               std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-                               std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
+    IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container);
     ~IApplicationDisplayService() override;
     ~IApplicationDisplayService() override;
 
 
-    std::shared_ptr<FbshareBufferManager> GetSharedBufferManager() const {
-        return m_shared_buffer_manager;
+    std::shared_ptr<Container> GetContainer() const {
+        return m_container;
     }
     }
 
 
-private:
+public:
     Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service);
     Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service);
     Result GetSystemDisplayService(
     Result GetSystemDisplayService(
         Out<SharedPointer<ISystemDisplayService>> out_system_display_service);
         Out<SharedPointer<ISystemDisplayService>> out_system_display_service);
@@ -66,10 +68,13 @@ private:
                                                    s64 width, s64 height);
                                                    s64 width, s64 height);
 
 
 private:
 private:
-    const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
-    const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger;
-    const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
-    std::vector<u64> m_stray_layer_ids;
+    const std::shared_ptr<Container> m_container;
+
+    KernelHelpers::ServiceContext m_context;
+    std::mutex m_lock{};
+    std::set<u64> m_open_layer_ids{};
+    std::set<u64> m_stray_layer_ids{};
+    std::map<u64, Event> m_display_vsync_events{};
     bool m_vsync_event_fetched{false};
     bool m_vsync_event_fetched{false};
 };
 };
 
 

+ 6 - 7
src/core/hle/service/vi/application_root_service.cpp

@@ -4,17 +4,16 @@
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/vi/application_display_service.h"
 #include "core/hle/service/vi/application_display_service.h"
 #include "core/hle/service/vi/application_root_service.h"
 #include "core/hle/service/vi/application_root_service.h"
+#include "core/hle/service/vi/container.h"
 #include "core/hle/service/vi/service_creator.h"
 #include "core/hle/service/vi/service_creator.h"
 #include "core/hle/service/vi/vi.h"
 #include "core/hle/service/vi/vi.h"
 #include "core/hle/service/vi/vi_types.h"
 #include "core/hle/service/vi/vi_types.h"
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-IApplicationRootService::IApplicationRootService(
-    Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-    std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
-    : ServiceFramework{system_, "vi:u"}, m_binder_service{std::move(binder_service)},
-      m_shared_buffer_manager{std::move(shared_buffer_manager)} {
+IApplicationRootService::IApplicationRootService(Core::System& system_,
+                                                 std::shared_ptr<Container> container)
+    : ServiceFramework{system_, "vi:u"}, m_container{std::move(container)} {
     static const FunctionInfo functions[] = {
     static const FunctionInfo functions[] = {
         {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"},
         {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"},
         {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
         {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -27,8 +26,8 @@ IApplicationRootService::~IApplicationRootService() = default;
 Result IApplicationRootService::GetDisplayService(
 Result IApplicationRootService::GetDisplayService(
     Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
     Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
     LOG_DEBUG(Service_VI, "called");
     LOG_DEBUG(Service_VI, "called");
-    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service,
-                                          m_shared_buffer_manager, Permission::User, policy));
+    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
+                                          Permission::User, policy));
 }
 }
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 3 - 10
src/core/hle/service/vi/application_root_service.h

@@ -10,21 +10,15 @@ namespace Core {
 class System;
 class System;
 }
 }
 
 
-namespace Service::Nvnflinger {
-class IHOSBinderDriver;
-} // namespace Service::Nvnflinger
-
 namespace Service::VI {
 namespace Service::VI {
 
 
-class FbshareBufferManager;
+class Container;
 class IApplicationDisplayService;
 class IApplicationDisplayService;
 enum class Policy : u32;
 enum class Policy : u32;
 
 
 class IApplicationRootService final : public ServiceFramework<IApplicationRootService> {
 class IApplicationRootService final : public ServiceFramework<IApplicationRootService> {
 public:
 public:
-    explicit IApplicationRootService(Core::System& system_,
-                                     std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-                                     std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
+    explicit IApplicationRootService(Core::System& system_, std::shared_ptr<Container> container);
     ~IApplicationRootService() override;
     ~IApplicationRootService() override;
 
 
 private:
 private:
@@ -33,8 +27,7 @@ private:
         Policy policy);
         Policy policy);
 
 
 private:
 private:
-    const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
-    const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
+    const std::shared_ptr<Container> m_container;
 };
 };
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 114 - 0
src/core/hle/service/vi/conductor.cpp

@@ -0,0 +1,114 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/settings.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/service/vi/conductor.h"
+#include "core/hle/service/vi/container.h"
+#include "core/hle/service/vi/display_list.h"
+#include "core/hle/service/vi/vsync_manager.h"
+
+constexpr auto FrameNs = std::chrono::nanoseconds{1000000000 / 60};
+
+namespace Service::VI {
+
+Conductor::Conductor(Core::System& system, Container& container, DisplayList& displays)
+    : m_system(system), m_container(container) {
+    displays.ForEachDisplay([&](Display& display) {
+        m_vsync_managers.insert({display.GetId(), VsyncManager{}});
+    });
+
+    if (system.IsMulticore()) {
+        m_event = Core::Timing::CreateEvent(
+            "ScreenComposition",
+            [this](s64 time,
+                   std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
+                m_signal.Set();
+                return std::chrono::nanoseconds(this->GetNextTicks());
+            });
+
+        system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
+        m_thread = std::jthread([this](std::stop_token token) { this->VsyncThread(token); });
+    } else {
+        m_event = Core::Timing::CreateEvent(
+            "ScreenComposition",
+            [this](s64 time,
+                   std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
+                this->ProcessVsync();
+                return std::chrono::nanoseconds(this->GetNextTicks());
+            });
+
+        system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
+    }
+}
+
+Conductor::~Conductor() {
+    m_system.CoreTiming().UnscheduleEvent(m_event);
+
+    if (m_system.IsMulticore()) {
+        m_thread.request_stop();
+        m_signal.Set();
+    }
+}
+
+void Conductor::LinkVsyncEvent(u64 display_id, Event* event) {
+    if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) {
+        it->second.LinkVsyncEvent(event);
+    }
+}
+
+void Conductor::UnlinkVsyncEvent(u64 display_id, Event* event) {
+    if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) {
+        it->second.UnlinkVsyncEvent(event);
+    }
+}
+
+void Conductor::ProcessVsync() {
+    for (auto& [display_id, manager] : m_vsync_managers) {
+        m_container.ComposeOnDisplay(&m_swap_interval, &m_compose_speed_scale, display_id);
+        manager.SignalVsync();
+    }
+}
+
+void Conductor::VsyncThread(std::stop_token token) {
+    Common::SetCurrentThreadName("VSyncThread");
+
+    while (!token.stop_requested()) {
+        m_signal.Wait();
+
+        if (m_system.IsShuttingDown()) {
+            return;
+        }
+
+        this->ProcessVsync();
+    }
+}
+
+s64 Conductor::GetNextTicks() const {
+    const auto& settings = Settings::values;
+    auto speed_scale = 1.f;
+    if (settings.use_multi_core.GetValue()) {
+        if (settings.use_speed_limit.GetValue()) {
+            // Scales the speed based on speed_limit setting on MC. SC is handled by
+            // SpeedLimiter::DoSpeedLimiting.
+            speed_scale = 100.f / settings.speed_limit.GetValue();
+        } else {
+            // Run at unlocked framerate.
+            speed_scale = 0.01f;
+        }
+    }
+
+    // Adjust by speed limit determined during composition.
+    speed_scale /= m_compose_speed_scale;
+
+    if (m_system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
+        // Run at intended presentation rate during video playback.
+        speed_scale = 1.f;
+    }
+
+    const f32 effective_fps = 60.f / static_cast<f32>(m_swap_interval);
+    return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
+}
+
+} // namespace Service::VI

+ 57 - 0
src/core/hle/service/vi/conductor.h

@@ -0,0 +1,57 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+
+#include "common/common_types.h"
+#include "common/polyfill_thread.h"
+#include "common/thread.h"
+
+namespace Core {
+class System;
+}
+
+namespace Core::Timing {
+struct EventType;
+}
+
+namespace Service {
+class Event;
+}
+
+namespace Service::VI {
+
+class Container;
+class DisplayList;
+class VsyncManager;
+
+class Conductor {
+public:
+    explicit Conductor(Core::System& system, Container& container, DisplayList& displays);
+    ~Conductor();
+
+    void LinkVsyncEvent(u64 display_id, Event* event);
+    void UnlinkVsyncEvent(u64 display_id, Event* event);
+
+private:
+    void ProcessVsync();
+    void VsyncThread(std::stop_token token);
+    s64 GetNextTicks() const;
+
+private:
+    Core::System& m_system;
+    Container& m_container;
+    std::unordered_map<u64, VsyncManager> m_vsync_managers;
+    std::shared_ptr<Core::Timing::EventType> m_event;
+    Common::Event m_signal;
+    std::jthread m_thread;
+
+private:
+    s32 m_swap_interval = 1;
+    f32 m_compose_speed_scale = 1.0f;
+};
+
+} // namespace Service::VI

+ 227 - 0
src/core/hle/service/vi/container.cpp

@@ -0,0 +1,227 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/service/nvdrv/nvdrv_interface.h"
+#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
+#include "core/hle/service/nvnflinger/surface_flinger.h"
+#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/vi/container.h"
+#include "core/hle/service/vi/vi_results.h"
+
+namespace Service::VI {
+
+Container::Container(Core::System& system) {
+    m_displays.CreateDisplay(DisplayName{"Default"});
+    m_displays.CreateDisplay(DisplayName{"External"});
+    m_displays.CreateDisplay(DisplayName{"Edid"});
+    m_displays.CreateDisplay(DisplayName{"Internal"});
+    m_displays.CreateDisplay(DisplayName{"Null"});
+
+    m_binder_driver =
+        system.ServiceManager().GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true);
+    m_surface_flinger = m_binder_driver->GetSurfaceFlinger();
+
+    const auto nvdrv =
+        system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
+    m_shared_buffer_manager.emplace(system, *this, nvdrv);
+
+    m_displays.ForEachDisplay(
+        [&](auto& display) { m_surface_flinger->AddDisplay(display.GetId()); });
+
+    m_conductor.emplace(system, *this, m_displays);
+}
+
+Container::~Container() {
+    this->OnTerminate();
+}
+
+void Container::OnTerminate() {
+    std::scoped_lock lk{m_lock};
+
+    m_is_shut_down = true;
+
+    m_layers.ForEachLayer([&](auto& layer) {
+        if (layer.IsOpen()) {
+            this->DestroyBufferQueueLocked(&layer);
+        }
+    });
+
+    m_displays.ForEachDisplay(
+        [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); });
+}
+
+SharedBufferManager* Container::GetSharedBufferManager() {
+    return std::addressof(*m_shared_buffer_manager);
+}
+
+Result Container::GetBinderDriver(
+    std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver) {
+    *out_binder_driver = m_binder_driver;
+    R_SUCCEED();
+}
+
+Result Container::GetLayerProducerHandle(
+    std::shared_ptr<android::BufferQueueProducer>* out_producer, u64 layer_id) {
+    std::scoped_lock lk{m_lock};
+
+    auto* const layer = m_layers.GetLayerById(layer_id);
+    R_UNLESS(layer != nullptr, VI::ResultNotFound);
+
+    const auto binder = m_binder_driver->GetServer()->TryGetBinder(layer->GetProducerBinderId());
+    R_UNLESS(binder != nullptr, VI::ResultNotFound);
+
+    *out_producer = std::static_pointer_cast<android::BufferQueueProducer>(binder);
+    R_SUCCEED();
+}
+
+Result Container::OpenDisplay(u64* out_display_id, const DisplayName& display_name) {
+    auto* const display = m_displays.GetDisplayByName(display_name);
+    R_UNLESS(display != nullptr, VI::ResultNotFound);
+
+    *out_display_id = display->GetId();
+    R_SUCCEED();
+}
+
+Result Container::CloseDisplay(u64 display_id) {
+    R_SUCCEED();
+}
+
+Result Container::CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid) {
+    std::scoped_lock lk{m_lock};
+    R_RETURN(this->CreateLayerLocked(out_layer_id, display_id, owner_aruid));
+}
+
+Result Container::DestroyManagedLayer(u64 layer_id) {
+    std::scoped_lock lk{m_lock};
+
+    // Try to close, if open, but don't fail if not.
+    this->CloseLayerLocked(layer_id);
+
+    R_RETURN(this->DestroyLayerLocked(layer_id));
+}
+
+Result Container::OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
+    std::scoped_lock lk{m_lock};
+    R_RETURN(this->OpenLayerLocked(out_producer_binder_id, layer_id, aruid));
+}
+
+Result Container::CloseLayer(u64 layer_id) {
+    std::scoped_lock lk{m_lock};
+    R_RETURN(this->CloseLayerLocked(layer_id));
+}
+
+Result Container::SetLayerVisibility(u64 layer_id, bool visible) {
+    std::scoped_lock lk{m_lock};
+
+    auto* const layer = m_layers.GetLayerById(layer_id);
+    R_UNLESS(layer != nullptr, VI::ResultNotFound);
+
+    m_surface_flinger->SetLayerVisibility(layer->GetConsumerBinderId(), visible);
+    R_SUCCEED();
+}
+
+Result Container::SetLayerBlending(u64 layer_id, bool enabled) {
+    std::scoped_lock lk{m_lock};
+
+    auto* const layer = m_layers.GetLayerById(layer_id);
+    R_UNLESS(layer != nullptr, VI::ResultNotFound);
+
+    m_surface_flinger->SetLayerBlending(layer->GetConsumerBinderId(),
+                                        enabled ? Nvnflinger::LayerBlending::Coverage
+                                                : Nvnflinger::LayerBlending::None);
+    R_SUCCEED();
+}
+
+void Container::LinkVsyncEvent(u64 display_id, Event* event) {
+    std::scoped_lock lk{m_lock};
+    m_conductor->LinkVsyncEvent(display_id, event);
+}
+
+void Container::UnlinkVsyncEvent(u64 display_id, Event* event) {
+    std::scoped_lock lk{m_lock};
+    m_conductor->UnlinkVsyncEvent(display_id, event);
+}
+
+Result Container::CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id) {
+    std::scoped_lock lk{m_lock};
+    R_TRY(this->CreateLayerLocked(out_layer_id, display_id, {}));
+    R_RETURN(this->OpenLayerLocked(out_producer_binder_id, *out_layer_id, {}));
+}
+
+Result Container::DestroyStrayLayer(u64 layer_id) {
+    std::scoped_lock lk{m_lock};
+    R_TRY(this->CloseLayerLocked(layer_id));
+    R_RETURN(this->DestroyLayerLocked(layer_id));
+}
+
+Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid) {
+    auto* const display = m_displays.GetDisplayById(display_id);
+    R_UNLESS(display != nullptr, VI::ResultNotFound);
+
+    auto* const layer = m_layers.CreateLayer(owner_aruid, display);
+    R_UNLESS(layer != nullptr, VI::ResultNotFound);
+
+    *out_layer_id = layer->GetId();
+    R_SUCCEED();
+}
+
+Result Container::DestroyLayerLocked(u64 layer_id) {
+    R_SUCCEED_IF(m_layers.DestroyLayer(layer_id));
+    R_THROW(VI::ResultNotFound);
+}
+
+Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
+    R_UNLESS(!m_is_shut_down, VI::ResultOperationFailed);
+
+    auto* const layer = m_layers.GetLayerById(layer_id);
+    R_UNLESS(layer != nullptr, VI::ResultNotFound);
+    R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed);
+    R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied);
+
+    this->CreateBufferQueueLocked(layer);
+    *out_producer_binder_id = layer->GetProducerBinderId();
+
+    R_SUCCEED();
+}
+
+Result Container::CloseLayerLocked(u64 layer_id) {
+    auto* const layer = m_layers.GetLayerById(layer_id);
+    R_UNLESS(layer != nullptr, VI::ResultNotFound);
+    R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed);
+
+    this->DestroyBufferQueueLocked(layer);
+
+    R_SUCCEED();
+}
+
+void Container::CreateBufferQueueLocked(Layer* layer) {
+    s32 consumer_binder_id, producer_binder_id;
+    m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
+    layer->Open(consumer_binder_id, producer_binder_id);
+
+    if (auto* display = layer->GetDisplay(); display != nullptr) {
+        m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id);
+    }
+}
+
+void Container::DestroyBufferQueueLocked(Layer* layer) {
+    if (auto* display = layer->GetDisplay(); display != nullptr) {
+        m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
+                                                       layer->GetConsumerBinderId());
+    }
+
+    layer->Close();
+    m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
+                                          layer->GetProducerBinderId());
+}
+
+void Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
+                                 u64 display_id) {
+    std::scoped_lock lk{m_lock};
+    m_surface_flinger->ComposeDisplay(out_swap_interval, out_compose_speed_scale, display_id);
+}
+
+} // namespace Service::VI

+ 92 - 0
src/core/hle/service/vi/container.h

@@ -0,0 +1,92 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <optional>
+
+#include "core/hle/service/vi/conductor.h"
+#include "core/hle/service/vi/display_list.h"
+#include "core/hle/service/vi/layer_list.h"
+#include "core/hle/service/vi/shared_buffer_manager.h"
+
+union Result;
+
+namespace Service::android {
+class BufferQueueProducer;
+}
+
+namespace Service::Nvnflinger {
+class IHOSBinderDriver;
+class SurfaceFlinger;
+} // namespace Service::Nvnflinger
+
+namespace Service {
+class Event;
+}
+
+namespace Service::VI {
+
+class SharedBufferManager;
+
+class Container {
+public:
+    explicit Container(Core::System& system);
+    ~Container();
+
+    void OnTerminate();
+
+    SharedBufferManager* GetSharedBufferManager();
+
+    Result GetBinderDriver(std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver);
+    Result GetLayerProducerHandle(std::shared_ptr<android::BufferQueueProducer>* out_producer,
+                                  u64 layer_id);
+
+    Result OpenDisplay(u64* out_display_id, const DisplayName& display_name);
+    Result CloseDisplay(u64 display_id);
+
+    // Managed layers are created by the interaction between am and ommdisp
+    // on behalf of an applet. Their lifetime ends with the lifetime of the
+    // applet's ISelfController.
+    Result CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid);
+    Result DestroyManagedLayer(u64 layer_id);
+    Result OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
+    Result CloseLayer(u64 layer_id);
+
+    // Stray layers are created by non-applet sysmodules. Their lifetime ends
+    // with the lifetime of the IApplicationDisplayService which created them.
+    Result CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id);
+    Result DestroyStrayLayer(u64 layer_id);
+
+    Result SetLayerVisibility(u64 layer_id, bool visible);
+    Result SetLayerBlending(u64 layer_id, bool enabled);
+
+    void LinkVsyncEvent(u64 display_id, Event* event);
+    void UnlinkVsyncEvent(u64 display_id, Event* event);
+
+private:
+    Result CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid);
+    Result DestroyLayerLocked(u64 layer_id);
+    Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
+    Result CloseLayerLocked(u64 layer_id);
+
+    void CreateBufferQueueLocked(Layer* layer);
+    void DestroyBufferQueueLocked(Layer* layer);
+
+public:
+    void ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
+
+private:
+    std::mutex m_lock{};
+    DisplayList m_displays{};
+    LayerList m_layers{};
+    std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_driver{};
+    std::shared_ptr<Nvnflinger::SurfaceFlinger> m_surface_flinger{};
+    std::optional<SharedBufferManager> m_shared_buffer_manager{};
+    std::optional<Conductor> m_conductor{};
+    bool m_is_shut_down{};
+};
+
+} // namespace Service::VI

+ 44 - 0
src/core/hle/service/vi/display.h

@@ -0,0 +1,44 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/vi/vi_types.h"
+
+namespace Service::VI {
+
+class Display {
+public:
+    constexpr Display() = default;
+
+    void Initialize(u64 id, const DisplayName& display_name) {
+        m_id = id;
+        m_display_name = display_name;
+        m_is_initialized = true;
+    }
+
+    void Finalize() {
+        m_id = {};
+        m_display_name = {};
+        m_is_initialized = {};
+    }
+
+    u64 GetId() const {
+        return m_id;
+    }
+
+    const DisplayName& GetDisplayName() const {
+        return m_display_name;
+    }
+
+    bool IsInitialized() const {
+        return m_is_initialized;
+    }
+
+private:
+    u64 m_id{};
+    DisplayName m_display_name{};
+    bool m_is_initialized{};
+};
+
+} // namespace Service::VI

+ 0 - 143
src/core/hle/service/vi/display/vi_display.cpp

@@ -1,143 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <algorithm>
-#include <utility>
-
-#include <fmt/format.h>
-
-#include "common/assert.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_readable_event.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/nvdrv/core/container.h"
-#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
-#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
-#include "core/hle/service/nvnflinger/buffer_queue_core.h"
-#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
-#include "core/hle/service/nvnflinger/hardware_composer.h"
-#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
-#include "core/hle/service/vi/display/vi_display.h"
-#include "core/hle/service/vi/layer/vi_layer.h"
-#include "core/hle/service/vi/vi_results.h"
-
-namespace Service::VI {
-
-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,
-                                     Service::Nvidia::NvCore::NvMap& nvmap) {
-    auto buffer_queue_core = std::make_shared<android::BufferQueueCore>();
-    return {
-        buffer_queue_core,
-        std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap),
-        std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
-}
-
-Display::Display(u64 id, std::string name_,
-                 Nvnflinger::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_} {
-    hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>();
-    vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
-}
-
-Display::~Display() {
-    service_context.CloseEvent(vsync_event);
-}
-
-Layer& Display::GetLayer(std::size_t index) {
-    size_t i = 0;
-    for (auto& layer : layers) {
-        if (!layer->IsOpen() || !layer->IsVisible()) {
-            continue;
-        }
-
-        if (i == index) {
-            return *layer;
-        }
-
-        i++;
-    }
-
-    UNREACHABLE();
-}
-
-size_t Display::GetNumLayers() const {
-    return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); });
-}
-
-Kernel::KReadableEvent* Display::GetVSyncEvent() {
-    return &vsync_event->GetReadableEvent();
-}
-
-void Display::SignalVSyncEvent() {
-    vsync_event->Signal();
-}
-
-void Display::CreateLayer(u64 layer_id, u32 binder_id,
-                          Service::Nvidia::NvCore::Container& nv_core) {
-    auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile());
-
-    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)));
-
-    if (is_abandoned) {
-        this->FindLayer(layer_id)->GetConsumer().Abandon();
-    }
-
-    hos_binder_driver_server.RegisterProducer(std::move(producer));
-}
-
-void Display::DestroyLayer(u64 layer_id) {
-    if (auto* layer = this->FindLayer(layer_id); layer != nullptr) {
-        layer->GetConsumer().Abandon();
-    }
-
-    std::erase_if(layers,
-                  [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
-}
-
-void Display::Abandon() {
-    for (auto& layer : layers) {
-        layer->GetConsumer().Abandon();
-    }
-    is_abandoned = true;
-}
-
-Layer* Display::FindLayer(u64 layer_id) {
-    const auto itr =
-        std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
-            return layer->GetLayerId() == layer_id;
-        });
-
-    if (itr == layers.end()) {
-        return nullptr;
-    }
-
-    return itr->get();
-}
-
-const Layer* Display::FindLayer(u64 layer_id) const {
-    const auto itr =
-        std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
-            return layer->GetLayerId() == layer_id;
-        });
-
-    if (itr == layers.end()) {
-        return nullptr;
-    }
-
-    return itr->get();
-}
-
-} // namespace Service::VI

+ 0 - 143
src/core/hle/service/vi/display/vi_display.h

@@ -1,143 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "common/common_funcs.h"
-#include "common/common_types.h"
-#include "core/hle/result.h"
-
-namespace Core {
-class System;
-}
-
-namespace Kernel {
-class KEvent;
-class KReadableEvent;
-} // namespace Kernel
-
-namespace Service::android {
-class BufferQueueProducer;
-}
-
-namespace Service::KernelHelpers {
-class ServiceContext;
-}
-
-namespace Service::Nvnflinger {
-class HardwareComposer;
-class HosBinderDriverServer;
-} // namespace Service::Nvnflinger
-
-namespace Service::Nvidia::NvCore {
-class Container;
-class NvMap;
-} // namespace Service::Nvidia::NvCore
-
-namespace Service::VI {
-
-class Layer;
-
-/// Represents a single display type
-class Display {
-public:
-    YUZU_NON_COPYABLE(Display);
-    YUZU_NON_MOVEABLE(Display);
-
-    /// Constructs a display with a given unique ID and name.
-    ///
-    /// @param id The unique ID for this display.
-    /// @param hos_binder_driver_server_ Nvnflinger 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_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
-            KernelHelpers::ServiceContext& service_context_, Core::System& system_);
-    ~Display();
-
-    /// Gets the unique ID assigned to this display.
-    u64 GetID() const {
-        return display_id;
-    }
-
-    /// Gets the name of this display
-    const std::string& GetName() const {
-        return name;
-    }
-
-    /// Whether or not this display has any layers added to it.
-    bool HasLayers() const {
-        return GetNumLayers() > 0;
-    }
-
-    /// Gets a layer for this display based off an index.
-    Layer& GetLayer(std::size_t index);
-
-    std::size_t GetNumLayers() const;
-
-    /// Gets the internal vsync event.
-    Kernel::KReadableEvent* GetVSyncEvent();
-
-    /// Signals the internal vsync event.
-    void SignalVSyncEvent();
-
-    /// Creates and adds a layer to this display with the given ID.
-    ///
-    /// @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, u32 binder_id, Service::Nvidia::NvCore::Container& core);
-
-    /// Removes a layer from this display with the given ID.
-    ///
-    /// @param layer_id The ID assigned to the layer to destroy.
-    ///
-    void DestroyLayer(u64 layer_id);
-
-    /// Resets the display for a new connection.
-    void Reset() {
-        layers.clear();
-    }
-
-    void Abandon();
-
-    /// Attempts to find a layer with the given ID.
-    ///
-    /// @param layer_id The layer ID.
-    ///
-    /// @returns If found, the Layer instance with the given ID.
-    ///          If not found, then nullptr is returned.
-    ///
-    Layer* FindLayer(u64 layer_id);
-
-    /// Attempts to find a layer with the given ID.
-    ///
-    /// @param layer_id The layer ID.
-    ///
-    /// @returns If found, the Layer instance with the given ID.
-    ///          If not found, then nullptr is returned.
-    ///
-    const Layer* FindLayer(u64 layer_id) const;
-
-    Nvnflinger::HardwareComposer& GetComposer() const {
-        return *hardware_composer;
-    }
-
-private:
-    u64 display_id;
-    std::string name;
-    Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
-    KernelHelpers::ServiceContext& service_context;
-
-    std::vector<std::unique_ptr<Layer>> layers;
-    std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer;
-    Kernel::KEvent* vsync_event{};
-    bool is_abandoned{};
-};
-
-} // namespace Service::VI

+ 83 - 0
src/core/hle/service/vi/display_list.h

@@ -0,0 +1,83 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <cstring>
+
+#include "core/hle/service/vi/display.h"
+
+namespace Service::VI {
+
+class DisplayList {
+public:
+    constexpr DisplayList() = default;
+
+    bool CreateDisplay(const DisplayName& name) {
+        Display* const display = this->GetFreeDisplay();
+        if (!display) {
+            return false;
+        }
+
+        display->Initialize(m_next_id++, name);
+        return true;
+    }
+
+    bool DestroyDisplay(u64 display_id) {
+        Display* display = this->GetDisplayById(display_id);
+        if (!display) {
+            return false;
+        }
+
+        display->Finalize();
+        return true;
+    }
+
+    Display* GetDisplayByName(const DisplayName& name) {
+        for (auto& display : m_displays) {
+            if (display.IsInitialized() &&
+                std::strncmp(name.data(), display.GetDisplayName().data(), sizeof(DisplayName)) ==
+                    0) {
+                return &display;
+            }
+        }
+
+        return nullptr;
+    }
+
+    Display* GetDisplayById(u64 display_id) {
+        for (auto& display : m_displays) {
+            if (display.IsInitialized() && display.GetId() == display_id) {
+                return &display;
+            }
+        }
+
+        return nullptr;
+    }
+
+    template <typename F>
+    void ForEachDisplay(F&& cb) {
+        for (auto& display : m_displays) {
+            if (display.IsInitialized()) {
+                cb(display);
+            }
+        }
+    }
+
+private:
+    Display* GetFreeDisplay() {
+        for (auto& display : m_displays) {
+            if (!display.IsInitialized()) {
+                return &display;
+            }
+        }
+
+        return nullptr;
+    }
+
+private:
+    std::array<Display, 8> m_displays{};
+    u64 m_next_id{};
+};
+
+} // namespace Service::VI

+ 79 - 0
src/core/hle/service/vi/layer.h

@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Service::VI {
+
+class Display;
+
+class Layer {
+public:
+    constexpr Layer() = default;
+
+    void Initialize(u64 id, u64 owner_aruid, Display* display) {
+        m_id = id;
+        m_owner_aruid = owner_aruid;
+        m_display = display;
+        m_is_initialized = true;
+    }
+
+    void Finalize() {
+        m_id = {};
+        m_display = {};
+        m_is_initialized = {};
+    }
+
+    void Open(s32 consumer_binder_id, s32 producer_binder_id) {
+        m_consumer_binder_id = consumer_binder_id;
+        m_producer_binder_id = producer_binder_id;
+        m_is_open = true;
+    }
+
+    void Close() {
+        m_producer_binder_id = {};
+        m_consumer_binder_id = {};
+        m_is_open = {};
+    }
+
+    u64 GetId() const {
+        return m_id;
+    }
+
+    u64 GetOwnerAruid() const {
+        return m_owner_aruid;
+    }
+
+    Display* GetDisplay() const {
+        return m_display;
+    }
+
+    s32 GetConsumerBinderId() const {
+        return m_consumer_binder_id;
+    }
+
+    s32 GetProducerBinderId() const {
+        return m_producer_binder_id;
+    }
+
+    bool IsInitialized() const {
+        return m_is_initialized;
+    }
+
+    bool IsOpen() const {
+        return m_is_open;
+    }
+
+private:
+    u64 m_id{};
+    u64 m_owner_aruid{};
+    Display* m_display{};
+    s32 m_consumer_binder_id{};
+    s32 m_producer_binder_id{};
+    bool m_is_initialized{};
+    bool m_is_open{};
+};
+
+} // namespace Service::VI

+ 0 - 18
src/core/hle/service/vi/layer/vi_layer.cpp

@@ -1,18 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/nvnflinger/hwc_layer.h"
-#include "core/hle/service/vi/layer/vi_layer.h"
-
-namespace Service::VI {
-
-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_)},
-      blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
-
-Layer::~Layer() = default;
-
-} // namespace Service::VI

+ 0 - 118
src/core/hle/service/vi/layer/vi_layer.h

@@ -1,118 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <memory>
-#include <utility>
-
-#include "common/common_types.h"
-
-namespace Service::android {
-class BufferItemConsumer;
-class BufferQueueCore;
-class BufferQueueProducer;
-} // namespace Service::android
-
-namespace Service::Nvnflinger {
-enum class LayerBlending : u32;
-}
-
-namespace Service::VI {
-
-/// Represents a single display layer.
-class Layer {
-public:
-    /// Constructs a layer with a given ID and buffer queue.
-    ///
-    /// @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 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
-          android::BufferQueueProducer& binder_,
-          std::shared_ptr<android::BufferItemConsumer>&& consumer_);
-    ~Layer();
-
-    Layer(const Layer&) = delete;
-    Layer& operator=(const Layer&) = delete;
-
-    Layer(Layer&&) = default;
-    Layer& operator=(Layer&&) = delete;
-
-    /// Gets the ID for this layer.
-    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.
-    android::BufferQueueProducer& GetBufferQueue() {
-        return binder;
-    }
-
-    /// Gets a const reference to the buffer queue this layer is using.
-    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;
-    }
-
-    bool IsVisible() const {
-        return visible;
-    }
-
-    void SetVisibility(bool v) {
-        visible = v;
-    }
-
-    bool IsOpen() const {
-        return open;
-    }
-
-    bool Close() {
-        return std::exchange(open, false);
-    }
-
-    bool Open() {
-        return !std::exchange(open, true);
-    }
-
-    Nvnflinger::LayerBlending GetBlending() {
-        return blending;
-    }
-
-    void SetBlending(Nvnflinger::LayerBlending b) {
-        blending = b;
-    }
-
-private:
-    const u64 layer_id;
-    const u32 binder_id;
-    android::BufferQueueCore& core;
-    android::BufferQueueProducer& binder;
-    std::shared_ptr<android::BufferItemConsumer> consumer;
-    Service::Nvnflinger::LayerBlending blending;
-    bool open;
-    bool visible;
-};
-
-} // namespace Service::VI

+ 69 - 0
src/core/hle/service/vi/layer_list.h

@@ -0,0 +1,69 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/vi/layer.h"
+
+namespace Service::VI {
+
+class LayerList {
+public:
+    constexpr LayerList() = default;
+
+    Layer* CreateLayer(u64 owner_aruid, Display* display) {
+        Layer* const layer = GetFreeLayer();
+        if (!layer) {
+            return nullptr;
+        }
+
+        layer->Initialize(++m_next_id, owner_aruid, display);
+        return layer;
+    }
+
+    bool DestroyLayer(u64 layer_id) {
+        Layer* const layer = GetLayerById(layer_id);
+        if (!layer) {
+            return false;
+        }
+
+        layer->Finalize();
+        return true;
+    }
+
+    Layer* GetLayerById(u64 layer_id) {
+        for (auto& layer : m_layers) {
+            if (layer.IsInitialized() && layer.GetId() == layer_id) {
+                return &layer;
+            }
+        }
+
+        return nullptr;
+    }
+
+    template <typename F>
+    void ForEachLayer(F&& cb) {
+        for (auto& layer : m_layers) {
+            if (layer.IsInitialized()) {
+                cb(layer);
+            }
+        }
+    }
+
+private:
+    Layer* GetFreeLayer() {
+        for (auto& layer : m_layers) {
+            if (!layer.IsInitialized()) {
+                return &layer;
+            }
+        }
+
+        return nullptr;
+    }
+
+private:
+    std::array<Layer, 8> m_layers{};
+    u64 m_next_id{};
+};
+
+} // namespace Service::VI

+ 29 - 20
src/core/hle/service/vi/manager_display_service.cpp

@@ -2,23 +2,21 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/cmif_serialization.h"
-#include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/vi/container.h"
 #include "core/hle/service/vi/manager_display_service.h"
 #include "core/hle/service/vi/manager_display_service.h"
-#include "core/hle/service/vi/vi_results.h"
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-IManagerDisplayService::IManagerDisplayService(
-    Core::System& system_, std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger)
-    : ServiceFramework{system_, "IManagerDisplayService"},
-      m_surface_flinger{std::move(surface_flinger)} {
+IManagerDisplayService::IManagerDisplayService(Core::System& system_,
+                                               std::shared_ptr<Container> container)
+    : ServiceFramework{system_, "IManagerDisplayService"}, m_container{std::move(container)} {
     // clang-format off
     // clang-format off
     static const FunctionInfo functions[] = {
     static const FunctionInfo functions[] = {
         {200, nullptr, "AllocateProcessHeapBlock"},
         {200, nullptr, "AllocateProcessHeapBlock"},
         {201, nullptr, "FreeProcessHeapBlock"},
         {201, nullptr, "FreeProcessHeapBlock"},
         {1102, nullptr, "GetDisplayResolution"},
         {1102, nullptr, "GetDisplayResolution"},
         {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"},
         {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"},
-        {2011, nullptr, "DestroyManagedLayer"},
+        {2011, C<&IManagerDisplayService::DestroyManagedLayer>, "DestroyManagedLayer"},
         {2012, nullptr, "CreateStrayLayer"},
         {2012, nullptr, "CreateStrayLayer"},
         {2050, nullptr, "CreateIndirectLayer"},
         {2050, nullptr, "CreateIndirectLayer"},
         {2051, nullptr, "DestroyIndirectLayer"},
         {2051, nullptr, "DestroyIndirectLayer"},
@@ -103,19 +101,30 @@ IManagerDisplayService::IManagerDisplayService(
 
 
 IManagerDisplayService::~IManagerDisplayService() = default;
 IManagerDisplayService::~IManagerDisplayService() = default;
 
 
-Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 unknown,
-                                                  u64 display_id, AppletResourceUserId aruid) {
-    LOG_WARNING(Service_VI, "(STUBBED) called. unknown={}, display={}, aruid={}", unknown,
-                display_id, aruid.pid);
+Result IManagerDisplayService::CreateSharedLayerSession(Kernel::KProcess* owner_process,
+                                                        u64* out_buffer_id, u64* out_layer_handle,
+                                                        u64 display_id, bool enable_blending) {
+    R_RETURN(m_container->GetSharedBufferManager()->CreateSession(
+        owner_process, out_buffer_id, out_layer_handle, display_id, enable_blending));
+}
 
 
-    const auto layer_id = m_surface_flinger->CreateLayer(display_id);
-    if (!layer_id) {
-        LOG_ERROR(Service_VI, "Layer not found! display={}", display_id);
-        R_THROW(VI::ResultNotFound);
-    }
+void IManagerDisplayService::DestroySharedLayerSession(Kernel::KProcess* owner_process) {
+    m_container->GetSharedBufferManager()->DestroySession(owner_process);
+}
 
 
-    *out_layer_id = *layer_id;
-    R_SUCCEED();
+Result IManagerDisplayService::SetLayerBlending(bool enabled, u64 layer_id) {
+    R_RETURN(m_container->SetLayerBlending(layer_id, enabled));
+}
+
+Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,
+                                                  AppletResourceUserId aruid) {
+    LOG_DEBUG(Service_VI, "called. flags={}, display={}, aruid={}", flags, display_id, aruid.pid);
+    R_RETURN(m_container->CreateManagedLayer(out_layer_id, display_id, aruid.pid));
+}
+
+Result IManagerDisplayService::DestroyManagedLayer(u64 layer_id) {
+    LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
+    R_RETURN(m_container->DestroyManagedLayer(layer_id));
 }
 }
 
 
 Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
 Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
@@ -124,8 +133,8 @@ Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
 }
 }
 
 
 Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
 Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
-    LOG_WARNING(Service_VI, "(STUBBED) called, layer_id={}, visible={}", layer_id, visible);
-    R_SUCCEED();
+    LOG_DEBUG(Service_VI, "called, layer_id={}, visible={}", layer_id, visible);
+    R_RETURN(m_container->SetLayerVisibility(layer_id, visible));
 }
 }
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 17 - 5
src/core/hle/service/vi/manager_display_service.h

@@ -4,22 +4,34 @@
 #include "core/hle/service/cmif_types.h"
 #include "core/hle/service/cmif_types.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
 
 
+namespace Kernel {
+class KProcess;
+}
+
 namespace Service::VI {
 namespace Service::VI {
 
 
+class Container;
+
 class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
 class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
 public:
 public:
-    explicit IManagerDisplayService(Core::System& system_,
-                                    std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger);
+    explicit IManagerDisplayService(Core::System& system_, std::shared_ptr<Container> container);
     ~IManagerDisplayService() override;
     ~IManagerDisplayService() override;
 
 
-private:
-    Result CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, u64 display_id,
+    Result CreateSharedLayerSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
+                                    u64* out_layer_handle, u64 display_id, bool enable_blending);
+    void DestroySharedLayerSession(Kernel::KProcess* owner_process);
+
+    Result SetLayerBlending(bool enabled, u64 layer_id);
+
+public:
+    Result CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,
                               AppletResourceUserId aruid);
                               AppletResourceUserId aruid);
+    Result DestroyManagedLayer(u64 layer_id);
     Result AddToLayerStack(u32 stack_id, u64 layer_id);
     Result AddToLayerStack(u32 stack_id, u64 layer_id);
     Result SetLayerVisibility(bool visible, u64 layer_id);
     Result SetLayerVisibility(bool visible, u64 layer_id);
 
 
 private:
 private:
-    const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger;
+    const std::shared_ptr<Container> m_container;
 };
 };
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 6 - 7
src/core/hle/service/vi/manager_root_service.cpp

@@ -4,6 +4,7 @@
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver.h"
 #include "core/hle/service/nvnflinger/hos_binder_driver.h"
 #include "core/hle/service/vi/application_display_service.h"
 #include "core/hle/service/vi/application_display_service.h"
+#include "core/hle/service/vi/container.h"
 #include "core/hle/service/vi/manager_root_service.h"
 #include "core/hle/service/vi/manager_root_service.h"
 #include "core/hle/service/vi/service_creator.h"
 #include "core/hle/service/vi/service_creator.h"
 #include "core/hle/service/vi/vi.h"
 #include "core/hle/service/vi/vi.h"
@@ -11,11 +12,9 @@
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-IManagerRootService::IManagerRootService(
-    Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-    std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
-    : ServiceFramework{system_, "vi:m"}, m_binder_service{std::move(binder_service)},
-      m_shared_buffer_manager{std::move(shared_buffer_manager)} {
+IManagerRootService::IManagerRootService(Core::System& system_,
+                                         std::shared_ptr<Container> container)
+    : ServiceFramework{system_, "vi:m"}, m_container{std::move(container)} {
     static const FunctionInfo functions[] = {
     static const FunctionInfo functions[] = {
         {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"},
         {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"},
         {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
         {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -32,8 +31,8 @@ IManagerRootService::~IManagerRootService() = default;
 Result IManagerRootService::GetDisplayService(
 Result IManagerRootService::GetDisplayService(
     Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
     Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
     LOG_DEBUG(Service_VI, "called");
     LOG_DEBUG(Service_VI, "called");
-    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service,
-                                          m_shared_buffer_manager, Permission::Manager, policy));
+    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
+                                          Permission::Manager, policy));
 }
 }
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 3 - 10
src/core/hle/service/vi/manager_root_service.h

@@ -10,21 +10,15 @@ namespace Core {
 class System;
 class System;
 }
 }
 
 
-namespace Service::Nvnflinger {
-class IHOSBinderDriver;
-} // namespace Service::Nvnflinger
-
 namespace Service::VI {
 namespace Service::VI {
 
 
-class FbshareBufferManager;
+class Container;
 class IApplicationDisplayService;
 class IApplicationDisplayService;
 enum class Policy : u32;
 enum class Policy : u32;
 
 
 class IManagerRootService final : public ServiceFramework<IManagerRootService> {
 class IManagerRootService final : public ServiceFramework<IManagerRootService> {
 public:
 public:
-    explicit IManagerRootService(Core::System& system_,
-                                 std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-                                 std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
+    explicit IManagerRootService(Core::System& system_, std::shared_ptr<Container> container);
     ~IManagerRootService() override;
     ~IManagerRootService() override;
 
 
     Result GetDisplayService(
     Result GetDisplayService(
@@ -32,8 +26,7 @@ public:
         Policy policy);
         Policy policy);
 
 
 private:
 private:
-    const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
-    const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
+    const std::shared_ptr<Container> m_container;
 };
 };
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 2 - 3
src/core/hle/service/vi/service_creator.cpp

@@ -22,8 +22,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
 
 
 Result GetApplicationDisplayService(
 Result GetApplicationDisplayService(
     std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
     std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
-    Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-    std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission,
+    Core::System& system, std::shared_ptr<Container> container, Permission permission,
     Policy policy) {
     Policy policy) {
 
 
     if (!IsValidServiceAccess(permission, policy)) {
     if (!IsValidServiceAccess(permission, policy)) {
@@ -32,7 +31,7 @@ Result GetApplicationDisplayService(
     }
     }
 
 
     *out_application_display_service =
     *out_application_display_service =
-        std::make_shared<IApplicationDisplayService>(system, binder_service, shared_buffer_manager);
+        std::make_shared<IApplicationDisplayService>(system, std::move(container));
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 

+ 2 - 7
src/core/hle/service/vi/service_creator.h

@@ -11,23 +11,18 @@ namespace Core {
 class System;
 class System;
 }
 }
 
 
-namespace Service::Nvnflinger {
-class IHOSBinderDriver;
-} // namespace Service::Nvnflinger
-
 union Result;
 union Result;
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-class FbshareBufferManager;
+class Container;
 class IApplicationDisplayService;
 class IApplicationDisplayService;
 enum class Permission;
 enum class Permission;
 enum class Policy : u32;
 enum class Policy : u32;
 
 
 Result GetApplicationDisplayService(
 Result GetApplicationDisplayService(
     std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
     std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
-    Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-    std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission,
+    Core::System& system, std::shared_ptr<Container> container, Permission permission,
     Policy policy);
     Policy policy);
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 62 - 70
src/core/hle/service/vi/fbshare_buffer_manager.cpp → src/core/hle/service/vi/shared_buffer_manager.cpp

@@ -11,8 +11,8 @@
 #include "core/hle/service/nvnflinger/buffer_queue_producer.h"
 #include "core/hle/service/nvnflinger/buffer_queue_producer.h"
 #include "core/hle/service/nvnflinger/pixel_format.h"
 #include "core/hle/service/nvnflinger/pixel_format.h"
 #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
-#include "core/hle/service/vi/fbshare_buffer_manager.h"
-#include "core/hle/service/vi/layer/vi_layer.h"
+#include "core/hle/service/vi/container.h"
+#include "core/hle/service/vi/shared_buffer_manager.h"
 #include "core/hle/service/vi/vi_results.h"
 #include "core/hle/service/vi/vi_results.h"
 #include "video_core/gpu.h"
 #include "video_core/gpu.h"
 #include "video_core/host1x/host1x.h"
 #include "video_core/host1x/host1x.h"
@@ -203,16 +203,15 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han
 
 
 } // namespace
 } // namespace
 
 
-FbshareBufferManager::FbshareBufferManager(Core::System& system,
-                                           std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
-                                           std::shared_ptr<Nvidia::Module> nvdrv)
-    : m_system(system), m_surface_flinger(std::move(surface_flinger)), m_nvdrv(std::move(nvdrv)) {}
+SharedBufferManager::SharedBufferManager(Core::System& system, Container& container,
+                                         std::shared_ptr<Nvidia::Module> nvdrv)
+    : m_system(system), m_container(container), m_nvdrv(std::move(nvdrv)) {}
 
 
-FbshareBufferManager::~FbshareBufferManager() = default;
+SharedBufferManager::~SharedBufferManager() = default;
 
 
-Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id,
-                                        u64* out_layer_handle, u64 display_id,
-                                        Nvnflinger::LayerBlending blending) {
+Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
+                                          u64* out_layer_handle, u64 display_id,
+                                          bool enable_blending) {
     std::scoped_lock lk{m_guard};
     std::scoped_lock lk{m_guard};
 
 
     // Ensure we haven't already created.
     // Ensure we haven't already created.
@@ -237,7 +236,7 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
                                                  owner_process, m_system));
                                                  owner_process, m_system));
 
 
     // Create new session.
     // Create new session.
-    auto [it, was_emplaced] = m_sessions.emplace(aruid, FbshareSession{});
+    auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{});
     auto& session = it->second;
     auto& session = it->second;
 
 
     auto& container = m_nvdrv->GetContainer();
     auto& container = m_nvdrv->GetContainer();
@@ -249,17 +248,18 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
                                   session.nvmap_fd, map_address, SharedBufferSize));
                                   session.nvmap_fd, map_address, SharedBufferSize));
 
 
     // Create and open a layer for the display.
     // Create and open a layer for the display.
-    session.layer_id = m_surface_flinger->CreateLayer(m_display_id, blending).value();
-    m_surface_flinger->OpenLayer(session.layer_id);
+    s32 producer_binder_id;
+    R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
+                                       std::addressof(session.layer_id), display_id));
 
 
-    // Get the layer.
-    VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, session.layer_id);
-    ASSERT(layer != nullptr);
+    // Configure blending.
+    R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
 
 
     // Get the producer and set preallocated buffers.
     // Get the producer and set preallocated buffers.
-    auto& producer = layer->GetBufferQueue();
-    MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle);
-    MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle);
+    std::shared_ptr<android::BufferQueueProducer> producer;
+    R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id));
+    MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle);
+    MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle);
 
 
     // Assign outputs.
     // Assign outputs.
     *out_buffer_id = m_buffer_id;
     *out_buffer_id = m_buffer_id;
@@ -269,7 +269,7 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
-void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) {
+void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) {
     std::scoped_lock lk{m_guard};
     std::scoped_lock lk{m_guard};
 
 
     if (m_buffer_id == 0) {
     if (m_buffer_id == 0) {
@@ -285,7 +285,7 @@ void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) {
     auto& session = it->second;
     auto& session = it->second;
 
 
     // Destroy the layer.
     // Destroy the layer.
-    m_surface_flinger->DestroyLayer(session.layer_id);
+    R_ASSERT(m_container.DestroyStrayLayer(session.layer_id));
 
 
     // Close nvmap handle.
     // Close nvmap handle.
     FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
     FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
@@ -301,11 +301,11 @@ void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) {
     m_sessions.erase(it);
     m_sessions.erase(it);
 }
 }
 
 
-Result FbshareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
-                                                           s32* out_nvmap_handle,
-                                                           SharedMemoryPoolLayout* out_pool_layout,
-                                                           u64 buffer_id,
-                                                           u64 applet_resource_user_id) {
+Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
+                                                          s32* out_nvmap_handle,
+                                                          SharedMemoryPoolLayout* out_pool_layout,
+                                                          u64 buffer_id,
+                                                          u64 applet_resource_user_id) {
     std::scoped_lock lk{m_guard};
     std::scoped_lock lk{m_guard};
 
 
     R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
     R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
@@ -319,36 +319,20 @@ Result FbshareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
-Result FbshareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
-    // Ensure the layer id is valid.
-    R_UNLESS(layer_id > 0, VI::ResultNotFound);
-
-    // Get the layer.
-    VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, layer_id);
-    R_UNLESS(layer != nullptr, VI::ResultNotFound);
-
-    // We succeeded.
-    *out_layer = layer;
-    R_SUCCEED();
-}
-
-Result FbshareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
-                                                      std::array<s32, 4>& out_slot_indexes,
-                                                      s64* out_target_slot, u64 layer_id) {
+Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
+                                                     std::array<s32, 4>& out_slot_indexes,
+                                                     s64* out_target_slot, u64 layer_id) {
     std::scoped_lock lk{m_guard};
     std::scoped_lock lk{m_guard};
 
 
-    // Get the layer.
-    VI::Layer* layer;
-    R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
-
     // Get the producer.
     // Get the producer.
-    auto& producer = layer->GetBufferQueue();
+    std::shared_ptr<android::BufferQueueProducer> producer;
+    R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
 
 
     // Get the next buffer from the producer.
     // Get the next buffer from the producer.
     s32 slot;
     s32 slot;
-    R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0,
-                                    SharedBufferWidth, SharedBufferHeight,
-                                    SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
+    R_UNLESS(producer->DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0,
+                                     SharedBufferWidth, SharedBufferHeight,
+                                     SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
              VI::ResultOperationFailed);
              VI::ResultOperationFailed);
 
 
     // Assign remaining outputs.
     // Assign remaining outputs.
@@ -359,27 +343,24 @@ Result FbshareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
-Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
-                                                      Common::Rectangle<s32> crop_region,
-                                                      u32 transform, s32 swap_interval,
-                                                      u64 layer_id, s64 slot) {
+Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
+                                                     Common::Rectangle<s32> crop_region,
+                                                     u32 transform, s32 swap_interval, u64 layer_id,
+                                                     s64 slot) {
     std::scoped_lock lk{m_guard};
     std::scoped_lock lk{m_guard};
 
 
-    // Get the layer.
-    VI::Layer* layer;
-    R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
-
     // Get the producer.
     // Get the producer.
-    auto& producer = layer->GetBufferQueue();
+    std::shared_ptr<android::BufferQueueProducer> producer;
+    R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
 
 
     // Request to queue the buffer.
     // Request to queue the buffer.
     std::shared_ptr<android::GraphicBuffer> buffer;
     std::shared_ptr<android::GraphicBuffer> buffer;
-    R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
+    R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
                  android::Status::NoError,
                  android::Status::NoError,
              VI::ResultOperationFailed);
              VI::ResultOperationFailed);
 
 
     ON_RESULT_FAILURE {
     ON_RESULT_FAILURE {
-        producer.CancelBuffer(static_cast<s32>(slot), fence);
+        producer->CancelBuffer(static_cast<s32>(slot), fence);
     };
     };
 
 
     // Queue the buffer to the producer.
     // Queue the buffer to the producer.
@@ -389,7 +370,7 @@ Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
     input.fence = fence;
     input.fence = fence;
     input.transform = static_cast<android::NativeWindowTransform>(transform);
     input.transform = static_cast<android::NativeWindowTransform>(transform);
     input.swap_interval = swap_interval;
     input.swap_interval = swap_interval;
-    R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
+    R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
                  android::Status::NoError,
                  android::Status::NoError,
              VI::ResultOperationFailed);
              VI::ResultOperationFailed);
 
 
@@ -397,25 +378,36 @@ Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
-Result FbshareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
-                                                                 u64 layer_id) {
+Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
     std::scoped_lock lk{m_guard};
     std::scoped_lock lk{m_guard};
 
 
-    // Get the layer.
-    VI::Layer* layer;
-    R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
+    // Get the producer.
+    std::shared_ptr<android::BufferQueueProducer> producer;
+    R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
+
+    // Cancel.
+    producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence());
+
+    // We succeeded.
+    R_SUCCEED();
+}
+
+Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
+                                                                u64 layer_id) {
+    std::scoped_lock lk{m_guard};
 
 
     // Get the producer.
     // Get the producer.
-    auto& producer = layer->GetBufferQueue();
+    std::shared_ptr<android::BufferQueueProducer> producer;
+    R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
 
 
     // Set the event.
     // Set the event.
-    *out_event = std::addressof(producer.GetNativeHandle());
+    *out_event = producer->GetNativeHandle({});
 
 
     // We succeeded.
     // We succeeded.
     R_SUCCEED();
     R_SUCCEED();
 }
 }
 
 
-Result FbshareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
+Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
     std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
     std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
     Common::ScratchBuffer<u32> scratch;
     Common::ScratchBuffer<u32> scratch;
 
 

+ 25 - 16
src/core/hle/service/vi/fbshare_buffer_manager.h → src/core/hle/service/vi/shared_buffer_manager.h

@@ -8,16 +8,28 @@
 #include "common/math_util.h"
 #include "common/math_util.h"
 #include "core/hle/service/nvdrv/core/container.h"
 #include "core/hle/service/nvdrv/core/container.h"
 #include "core/hle/service/nvdrv/nvdata.h"
 #include "core/hle/service/nvdrv/nvdata.h"
-#include "core/hle/service/nvnflinger/hwc_layer.h"
 #include "core/hle/service/nvnflinger/nvnflinger.h"
 #include "core/hle/service/nvnflinger/nvnflinger.h"
 #include "core/hle/service/nvnflinger/ui/fence.h"
 #include "core/hle/service/nvnflinger/ui/fence.h"
 
 
 namespace Kernel {
 namespace Kernel {
 class KPageGroup;
 class KPageGroup;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Service::android {
+class BufferQueueProducer;
+}
+
+namespace Service::Nvidia {
+class Module;
 }
 }
 
 
+union Result;
+
 namespace Service::VI {
 namespace Service::VI {
 
 
+class Container;
+
 struct SharedMemorySlot {
 struct SharedMemorySlot {
     u64 buffer_offset;
     u64 buffer_offset;
     u64 size;
     u64 size;
@@ -32,18 +44,17 @@ struct SharedMemoryPoolLayout {
 };
 };
 static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
 static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
 
 
-struct FbshareSession;
+struct SharedBufferSession;
 
 
-class FbshareBufferManager final {
+class SharedBufferManager final {
 public:
 public:
-    explicit FbshareBufferManager(Core::System& system,
-                                  std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
-                                  std::shared_ptr<Nvidia::Module> nvdrv);
-    ~FbshareBufferManager();
+    explicit SharedBufferManager(Core::System& system, Container& container,
+                                 std::shared_ptr<Nvidia::Module> nvdrv);
+    ~SharedBufferManager();
 
 
-    Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
-                      u64 display_id, Nvnflinger::LayerBlending blending);
-    void Finalize(Kernel::KProcess* owner_process);
+    Result CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
+                         u64 display_id, bool enable_blending);
+    void DestroySession(Kernel::KProcess* owner_process);
 
 
     Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
     Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
                                          SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
                                          SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
@@ -52,28 +63,26 @@ public:
                                     s64* out_target_slot, u64 layer_id);
                                     s64* out_target_slot, u64 layer_id);
     Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
     Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
                                     u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
                                     u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
+    Result CancelSharedFrameBuffer(u64 layer_id, s64 slot);
     Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
     Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
 
 
     Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
     Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
 
 
-private:
-    Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
-
 private:
 private:
     u64 m_next_buffer_id = 1;
     u64 m_next_buffer_id = 1;
     u64 m_display_id = 0;
     u64 m_display_id = 0;
     u64 m_buffer_id = 0;
     u64 m_buffer_id = 0;
     SharedMemoryPoolLayout m_pool_layout = {};
     SharedMemoryPoolLayout m_pool_layout = {};
-    std::map<u64, FbshareSession> m_sessions;
+    std::map<u64, SharedBufferSession> m_sessions;
     std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
     std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
 
 
     std::mutex m_guard;
     std::mutex m_guard;
     Core::System& m_system;
     Core::System& m_system;
-    const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger;
+    Container& m_container;
     const std::shared_ptr<Nvidia::Module> m_nvdrv;
     const std::shared_ptr<Nvidia::Module> m_nvdrv;
 };
 };
 
 
-struct FbshareSession {
+struct SharedBufferSession {
     Nvidia::DeviceFD nvmap_fd = {};
     Nvidia::DeviceFD nvmap_fd = {};
     Nvidia::NvCore::SessionId session_id = {};
     Nvidia::NvCore::SessionId session_id = {};
     u64 layer_id = {};
     u64 layer_id = {};

+ 16 - 12
src/core/hle/service/vi/system_display_service.cpp

@@ -3,17 +3,15 @@
 
 
 #include "common/settings.h"
 #include "common/settings.h"
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/vi/container.h"
 #include "core/hle/service/vi/system_display_service.h"
 #include "core/hle/service/vi/system_display_service.h"
 #include "core/hle/service/vi/vi_types.h"
 #include "core/hle/service/vi/vi_types.h"
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-ISystemDisplayService::ISystemDisplayService(
-    Core::System& system_, std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
-    std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
-    : ServiceFramework{system_, "ISystemDisplayService"},
-      m_surface_flinger{std::move(surface_flinger)},
-      m_shared_buffer_manager{std::move(shared_buffer_manager)} {
+ISystemDisplayService::ISystemDisplayService(Core::System& system_,
+                                             std::shared_ptr<Container> container)
+    : ServiceFramework{system_, "ISystemDisplayService"}, m_container{std::move(container)} {
     // clang-format off
     // clang-format off
     static const FunctionInfo functions[] = {
     static const FunctionInfo functions[] = {
         {1200, nullptr, "GetZOrderCountMin"},
         {1200, nullptr, "GetZOrderCountMin"},
@@ -61,7 +59,7 @@ ISystemDisplayService::ISystemDisplayService(
         {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"},
         {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"},
         {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"},
         {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"},
         {8257, nullptr, "FillSharedFrameBufferColor"},
         {8257, nullptr, "FillSharedFrameBufferColor"},
-        {8258, nullptr, "CancelSharedFrameBuffer"},
+        {8258, C<&ISystemDisplayService::CancelSharedFrameBuffer>, "CancelSharedFrameBuffer"},
         {9000, nullptr, "GetDp2hdmiController"},
         {9000, nullptr, "GetDp2hdmiController"},
     };
     };
     // clang-format on
     // clang-format on
@@ -106,7 +104,7 @@ Result ISystemDisplayService::GetSharedBufferMemoryHandleId(
     ClientAppletResourceUserId aruid) {
     ClientAppletResourceUserId aruid) {
     LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid);
     LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid);
 
 
-    R_RETURN(m_shared_buffer_manager->GetSharedBufferMemoryHandleId(
+    R_RETURN(m_container->GetSharedBufferManager()->GetSharedBufferMemoryHandleId(
         out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid));
         out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid));
 }
 }
 
 
@@ -124,8 +122,8 @@ Result ISystemDisplayService::AcquireSharedFrameBuffer(Out<android::Fence> out_f
                                                        Out<std::array<s32, 4>> out_slots,
                                                        Out<std::array<s32, 4>> out_slots,
                                                        Out<s64> out_target_slot, u64 layer_id) {
                                                        Out<s64> out_target_slot, u64 layer_id) {
     LOG_DEBUG(Service_VI, "called");
     LOG_DEBUG(Service_VI, "called");
-    R_RETURN(m_shared_buffer_manager->AcquireSharedFrameBuffer(out_fence, *out_slots,
-                                                               out_target_slot, layer_id));
+    R_RETURN(m_container->GetSharedBufferManager()->AcquireSharedFrameBuffer(
+        out_fence, *out_slots, out_target_slot, layer_id));
 }
 }
 
 
 Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
 Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
@@ -133,14 +131,20 @@ Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
                                                        u32 window_transform, s32 swap_interval,
                                                        u32 window_transform, s32 swap_interval,
                                                        u64 layer_id, s64 surface_id) {
                                                        u64 layer_id, s64 surface_id) {
     LOG_DEBUG(Service_VI, "called");
     LOG_DEBUG(Service_VI, "called");
-    R_RETURN(m_shared_buffer_manager->PresentSharedFrameBuffer(
+    R_RETURN(m_container->GetSharedBufferManager()->PresentSharedFrameBuffer(
         fence, crop_region, window_transform, swap_interval, layer_id, surface_id));
         fence, crop_region, window_transform, swap_interval, layer_id, surface_id));
 }
 }
 
 
 Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent(
 Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent(
     OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) {
     OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) {
     LOG_DEBUG(Service_VI, "called");
     LOG_DEBUG(Service_VI, "called");
-    R_RETURN(m_shared_buffer_manager->GetSharedFrameBufferAcquirableEvent(out_event, layer_id));
+    R_RETURN(m_container->GetSharedBufferManager()->GetSharedFrameBufferAcquirableEvent(out_event,
+                                                                                        layer_id));
+}
+
+Result ISystemDisplayService::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
+    LOG_DEBUG(Service_VI, "called");
+    R_RETURN(m_container->GetSharedBufferManager()->CancelSharedFrameBuffer(layer_id, slot));
 }
 }
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 5 - 11
src/core/hle/service/vi/system_display_service.h

@@ -5,21 +5,15 @@
 #include "core/hle/service/cmif_types.h"
 #include "core/hle/service/cmif_types.h"
 #include "core/hle/service/nvnflinger/ui/fence.h"
 #include "core/hle/service/nvnflinger/ui/fence.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
-#include "core/hle/service/vi/fbshare_buffer_manager.h"
-
-namespace Service::Nvnflinger {
-class Nvnflinger;
-} // namespace Service::Nvnflinger
+#include "core/hle/service/vi/shared_buffer_manager.h"
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-class FbshareBufferManager;
+class Container;
 
 
 class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
 class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
 public:
 public:
-    explicit ISystemDisplayService(Core::System& system_,
-                                   std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
-                                   std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
+    explicit ISystemDisplayService(Core::System& system_, std::shared_ptr<Container> container);
     ~ISystemDisplayService() override;
     ~ISystemDisplayService() override;
 
 
 private:
 private:
@@ -42,10 +36,10 @@ private:
     Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
     Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
                                     u32 window_transform, s32 swap_interval, u64 layer_id,
                                     u32 window_transform, s32 swap_interval, u64 layer_id,
                                     s64 surface_id);
                                     s64 surface_id);
+    Result CancelSharedFrameBuffer(u64 layer_id, s64 slot);
 
 
 private:
 private:
-    const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger;
-    const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
+    const std::shared_ptr<Container> m_container;
 };
 };
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 5 - 7
src/core/hle/service/vi/system_root_service.cpp

@@ -3,6 +3,7 @@
 
 
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/cmif_serialization.h"
 #include "core/hle/service/vi/application_display_service.h"
 #include "core/hle/service/vi/application_display_service.h"
+#include "core/hle/service/vi/container.h"
 #include "core/hle/service/vi/service_creator.h"
 #include "core/hle/service/vi/service_creator.h"
 #include "core/hle/service/vi/system_root_service.h"
 #include "core/hle/service/vi/system_root_service.h"
 #include "core/hle/service/vi/vi.h"
 #include "core/hle/service/vi/vi.h"
@@ -10,11 +11,8 @@
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-ISystemRootService::ISystemRootService(Core::System& system_,
-                                       std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-                                       std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
-    : ServiceFramework{system_, "vi:s"}, m_binder_service{std::move(binder_service)},
-      m_shared_buffer_manager{std::move(shared_buffer_manager)} {
+ISystemRootService::ISystemRootService(Core::System& system_, std::shared_ptr<Container> container)
+    : ServiceFramework{system_, "vi:s"}, m_container{std::move(container)} {
     static const FunctionInfo functions[] = {
     static const FunctionInfo functions[] = {
         {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"},
         {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"},
         {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
         {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -27,8 +25,8 @@ ISystemRootService::~ISystemRootService() = default;
 Result ISystemRootService::GetDisplayService(
 Result ISystemRootService::GetDisplayService(
     Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
     Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
     LOG_DEBUG(Service_VI, "called");
     LOG_DEBUG(Service_VI, "called");
-    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service,
-                                          m_shared_buffer_manager, Permission::System, policy));
+    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
+                                          Permission::System, policy));
 }
 }
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 3 - 10
src/core/hle/service/vi/system_root_service.h

@@ -10,21 +10,15 @@ namespace Core {
 class System;
 class System;
 }
 }
 
 
-namespace Service::Nvnflinger {
-class IHOSBinderDriver;
-} // namespace Service::Nvnflinger
-
 namespace Service::VI {
 namespace Service::VI {
 
 
-class FbshareBufferManager;
+class Container;
 class IApplicationDisplayService;
 class IApplicationDisplayService;
 enum class Policy : u32;
 enum class Policy : u32;
 
 
 class ISystemRootService final : public ServiceFramework<ISystemRootService> {
 class ISystemRootService final : public ServiceFramework<ISystemRootService> {
 public:
 public:
-    explicit ISystemRootService(Core::System& system_,
-                                std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
-                                std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
+    explicit ISystemRootService(Core::System& system_, std::shared_ptr<Container> container);
     ~ISystemRootService() override;
     ~ISystemRootService() override;
 
 
 private:
 private:
@@ -32,8 +26,7 @@ private:
         Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
         Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
         Policy policy);
         Policy policy);
 
 
-    const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
-    const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
+    const std::shared_ptr<Container> m_container;
 };
 };
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 11 - 20
src/core/hle/service/vi/vi.cpp

@@ -2,38 +2,29 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 
 #include "core/core.h"
 #include "core/core.h"
-#include "core/hle/service/nvdrv/nvdrv_interface.h"
-#include "core/hle/service/nvnflinger/hos_binder_driver.h"
 #include "core/hle/service/server_manager.h"
 #include "core/hle/service/server_manager.h"
-#include "core/hle/service/sm/sm.h"
-#include "core/hle/service/vi/application_display_service.h"
 #include "core/hle/service/vi/application_root_service.h"
 #include "core/hle/service/vi/application_root_service.h"
-#include "core/hle/service/vi/fbshare_buffer_manager.h"
+#include "core/hle/service/vi/container.h"
 #include "core/hle/service/vi/manager_root_service.h"
 #include "core/hle/service/vi/manager_root_service.h"
 #include "core/hle/service/vi/system_root_service.h"
 #include "core/hle/service/vi/system_root_service.h"
 #include "core/hle/service/vi/vi.h"
 #include "core/hle/service/vi/vi.h"
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-void LoopProcess(Core::System& system) {
-    const auto binder_service =
-        system.ServiceManager().GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true);
-    const auto nvdrv =
-        system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
-    const auto shared_buffer_manager =
-        std::make_shared<FbshareBufferManager>(system, binder_service->GetSurfaceFlinger(), nvdrv);
+void LoopProcess(Core::System& system, std::stop_token token) {
+    const auto container = std::make_shared<Container>(system);
 
 
     auto server_manager = std::make_unique<ServerManager>(system);
     auto server_manager = std::make_unique<ServerManager>(system);
 
 
+    server_manager->RegisterNamedService("vi:m",
+                                         std::make_shared<IManagerRootService>(system, container));
+    server_manager->RegisterNamedService("vi:s",
+                                         std::make_shared<ISystemRootService>(system, container));
     server_manager->RegisterNamedService(
     server_manager->RegisterNamedService(
-        "vi:m",
-        std::make_shared<IManagerRootService>(system, binder_service, shared_buffer_manager));
-    server_manager->RegisterNamedService(
-        "vi:s",
-        std::make_shared<ISystemRootService>(system, binder_service, shared_buffer_manager));
-    server_manager->RegisterNamedService(
-        "vi:u",
-        std::make_shared<IApplicationRootService>(system, binder_service, shared_buffer_manager));
+        "vi:u", std::make_shared<IApplicationRootService>(system, container));
+
+    std::stop_callback cb(token, [=] { container->OnTerminate(); });
+
     ServerManager::RunServer(std::move(server_manager));
     ServerManager::RunServer(std::move(server_manager));
 }
 }
 
 

+ 3 - 1
src/core/hle/service/vi/vi.h

@@ -3,12 +3,14 @@
 
 
 #pragma once
 #pragma once
 
 
+#include "common/polyfill_thread.h"
+
 namespace Core {
 namespace Core {
 class System;
 class System;
 }
 }
 
 
 namespace Service::VI {
 namespace Service::VI {
 
 
-void LoopProcess(Core::System& system);
+void LoopProcess(Core::System& system, std::stop_token token);
 
 
 } // namespace Service::VI
 } // namespace Service::VI

+ 1 - 1
src/core/hle/service/vi/vi_types.h

@@ -68,7 +68,7 @@ static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
 
 
 class NativeWindow final {
 class NativeWindow final {
 public:
 public:
-    constexpr explicit NativeWindow(u32 id_) : id{id_} {}
+    constexpr explicit NativeWindow(s32 id_) : id{static_cast<u64>(id_)} {}
     constexpr explicit NativeWindow(const NativeWindow& other) = default;
     constexpr explicit NativeWindow(const NativeWindow& other) = default;
 
 
 private:
 private:

+ 26 - 0
src/core/hle/service/vi/vsync_manager.cpp

@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/os/event.h"
+#include "core/hle/service/vi/vsync_manager.h"
+
+namespace Service::VI {
+
+VsyncManager::VsyncManager() = default;
+VsyncManager::~VsyncManager() = default;
+
+void VsyncManager::SignalVsync() {
+    for (auto* event : m_vsync_events) {
+        event->Signal();
+    }
+}
+
+void VsyncManager::LinkVsyncEvent(Event* event) {
+    m_vsync_events.insert(event);
+}
+
+void VsyncManager::UnlinkVsyncEvent(Event* event) {
+    m_vsync_events.erase(event);
+}
+
+} // namespace Service::VI

+ 29 - 0
src/core/hle/service/vi/vsync_manager.h

@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <set>
+
+namespace Service {
+class Event;
+}
+
+namespace Service::VI {
+
+class DisplayList;
+
+class VsyncManager {
+public:
+    explicit VsyncManager();
+    ~VsyncManager();
+
+    void SignalVsync();
+    void LinkVsyncEvent(Event* event);
+    void UnlinkVsyncEvent(Event* event);
+
+private:
+    std::set<Event*> m_vsync_events;
+};
+
+} // namespace Service::VI