From 812f23d05c77fb10407546c3e7a95447fcbea395 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 14 Feb 2024 23:44:05 -0500 Subject: vi: manage resources independently of nvnflinger and refactor --- src/core/CMakeLists.txt | 22 +- src/core/core.cpp | 7 +- src/core/hle/service/am/display_layer_manager.cpp | 77 ++-- src/core/hle/service/am/display_layer_manager.h | 13 +- src/core/hle/service/nvdrv/nvdrv.h | 7 - src/core/hle/service/nvnflinger/binder.h | 23 +- .../service/nvnflinger/buffer_item_consumer.cpp | 2 +- .../hle/service/nvnflinger/buffer_item_consumer.h | 2 +- .../service/nvnflinger/buffer_queue_consumer.cpp | 76 +++- .../hle/service/nvnflinger/buffer_queue_consumer.h | 10 +- .../service/nvnflinger/buffer_queue_producer.cpp | 32 +- .../hle/service/nvnflinger/buffer_queue_producer.h | 8 +- src/core/hle/service/nvnflinger/consumer_base.cpp | 2 +- src/core/hle/service/nvnflinger/consumer_base.h | 4 +- src/core/hle/service/nvnflinger/display.h | 51 +++ .../hle/service/nvnflinger/hardware_composer.cpp | 65 ++- .../hle/service/nvnflinger/hardware_composer.h | 20 +- .../hle/service/nvnflinger/hos_binder_driver.cpp | 20 +- .../hle/service/nvnflinger/hos_binder_driver.h | 21 +- .../nvnflinger/hos_binder_driver_server.cpp | 22 +- .../service/nvnflinger/hos_binder_driver_server.h | 16 +- src/core/hle/service/nvnflinger/nvnflinger.cpp | 305 +------------- src/core/hle/service/nvnflinger/nvnflinger.h | 152 +------ .../hle/service/nvnflinger/surface_flinger.cpp | 123 ++++++ src/core/hle/service/nvnflinger/surface_flinger.h | 65 +++ src/core/hle/service/service.cpp | 126 ------ src/core/hle/service/service.h | 10 - src/core/hle/service/services.cpp | 136 +++++++ src/core/hle/service/services.h | 22 + .../hle/service/vi/application_display_service.cpp | 118 +++--- .../hle/service/vi/application_display_service.h | 31 +- .../hle/service/vi/application_root_service.cpp | 13 +- src/core/hle/service/vi/application_root_service.h | 13 +- src/core/hle/service/vi/conductor.cpp | 114 ++++++ src/core/hle/service/vi/conductor.h | 57 +++ src/core/hle/service/vi/container.cpp | 227 +++++++++++ src/core/hle/service/vi/container.h | 92 +++++ src/core/hle/service/vi/display.h | 44 ++ src/core/hle/service/vi/display/vi_display.cpp | 143 ------- src/core/hle/service/vi/display/vi_display.h | 143 ------- src/core/hle/service/vi/display_list.h | 83 ++++ src/core/hle/service/vi/fbshare_buffer_manager.cpp | 447 --------------------- src/core/hle/service/vi/fbshare_buffer_manager.h | 83 ---- src/core/hle/service/vi/layer.h | 79 ++++ src/core/hle/service/vi/layer/vi_layer.cpp | 18 - src/core/hle/service/vi/layer/vi_layer.h | 118 ------ src/core/hle/service/vi/layer_list.h | 69 ++++ .../hle/service/vi/manager_display_service.cpp | 49 ++- src/core/hle/service/vi/manager_display_service.h | 22 +- src/core/hle/service/vi/manager_root_service.cpp | 13 +- src/core/hle/service/vi/manager_root_service.h | 13 +- src/core/hle/service/vi/service_creator.cpp | 5 +- src/core/hle/service/vi/service_creator.h | 9 +- src/core/hle/service/vi/shared_buffer_manager.cpp | 439 ++++++++++++++++++++ src/core/hle/service/vi/shared_buffer_manager.h | 92 +++++ src/core/hle/service/vi/system_display_service.cpp | 28 +- src/core/hle/service/vi/system_display_service.h | 16 +- src/core/hle/service/vi/system_root_service.cpp | 12 +- src/core/hle/service/vi/system_root_service.h | 13 +- src/core/hle/service/vi/vi.cpp | 31 +- src/core/hle/service/vi/vi.h | 4 +- src/core/hle/service/vi/vi_types.h | 2 +- src/core/hle/service/vi/vsync_manager.cpp | 26 ++ src/core/hle/service/vi/vsync_manager.h | 29 ++ 64 files changed, 2200 insertions(+), 1934 deletions(-) create mode 100644 src/core/hle/service/nvnflinger/display.h create mode 100644 src/core/hle/service/nvnflinger/surface_flinger.cpp create mode 100644 src/core/hle/service/nvnflinger/surface_flinger.h create mode 100644 src/core/hle/service/services.cpp create mode 100644 src/core/hle/service/services.h create mode 100644 src/core/hle/service/vi/conductor.cpp create mode 100644 src/core/hle/service/vi/conductor.h create mode 100644 src/core/hle/service/vi/container.cpp create mode 100644 src/core/hle/service/vi/container.h create mode 100644 src/core/hle/service/vi/display.h delete mode 100644 src/core/hle/service/vi/display/vi_display.cpp delete mode 100644 src/core/hle/service/vi/display/vi_display.h create mode 100644 src/core/hle/service/vi/display_list.h delete mode 100644 src/core/hle/service/vi/fbshare_buffer_manager.cpp delete mode 100644 src/core/hle/service/vi/fbshare_buffer_manager.h create mode 100644 src/core/hle/service/vi/layer.h delete mode 100644 src/core/hle/service/vi/layer/vi_layer.cpp delete mode 100644 src/core/hle/service/vi/layer/vi_layer.h create mode 100644 src/core/hle/service/vi/layer_list.h create mode 100644 src/core/hle/service/vi/shared_buffer_manager.cpp create mode 100644 src/core/hle/service/vi/shared_buffer_manager.h create mode 100644 src/core/hle/service/vi/vsync_manager.cpp create mode 100644 src/core/hle/service/vi/vsync_manager.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index bf1268bbb..f70e093ca 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -813,6 +813,8 @@ add_library(core STATIC hle/service/nvnflinger/pixel_format.h hle/service/nvnflinger/producer_listener.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/graphic_buffer.cpp hle/service/nvnflinger/ui/graphic_buffer.h @@ -906,6 +908,8 @@ add_library(core STATIC hle/service/server_manager.h hle/service/service.cpp 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.h hle/service/set/setting_formats/device_settings.cpp @@ -953,22 +957,26 @@ add_library(core STATIC hle/service/ssl/ssl_backend.h hle/service/usb/usb.cpp 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.h hle/service/vi/application_root_service.cpp 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.h hle/service/vi/manager_root_service.cpp hle/service/vi/manager_root_service.h hle/service/vi/service_creator.cpp 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.h 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.cpp hle/service/vi/vi.h + hle/service/vi/vsync_manager.cpp + hle/service/vi/vsync_manager.h internal_network/network.cpp internal_network/network.h internal_network/network_interface.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 60e2efddc..9e8936728 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -47,6 +47,7 @@ #include "core/hle/service/psc/time/system_clock.h" #include "core/hle/service/psc/time/time_zone_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/sm/sm.h" #include "core/internal_network/network.h" @@ -310,7 +311,8 @@ struct System::Impl { audio_core = std::make_unique(system); service_manager = std::make_shared(kernel); - services = std::make_unique(service_manager, system); + services = + std::make_unique(service_manager, system, stop_event.get_token()); is_powered_on = true; exit_locked = false; @@ -458,6 +460,7 @@ struct System::Impl { gpu_core->NotifyShutdown(); } + stop_event.request_stop(); core_timing.SyncPause(false); Network::CancelPendingSocketOperations(); kernel.SuspendEmulation(true); @@ -478,6 +481,7 @@ struct System::Impl { cpu_manager.Shutdown(); debugger.reset(); kernel.Shutdown(); + stop_event = {}; Network::RestartSocketOperations(); if (auto room_member = room_network.GetRoomMember().lock()) { @@ -613,6 +617,7 @@ struct System::Impl { ExecuteProgramCallback execute_program_callback; ExitCallback exit_callback; + std::stop_source stop_event; std::array dynarmic_ticks{}; std::array microprofile_cpu{}; diff --git a/src/core/hle/service/am/display_layer_manager.cpp b/src/core/hle/service/am/display_layer_manager.cpp index dc742c1f6..85ff6fb88 100644 --- a/src/core/hle/service/am/display_layer_manager.cpp +++ b/src/core/hle/service/am/display_layer_manager.cpp @@ -3,11 +3,12 @@ #include "core/core.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/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/shared_buffer_manager.h" #include "core/hle/service/vi/vi_results.h" #include "core/hle/service/vi/vi_types.h" @@ -20,12 +21,10 @@ DisplayLayerManager::~DisplayLayerManager() { void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process, AppletId applet_id, LibraryAppletMode mode) { - m_surface_flinger = system.ServiceManager() - .GetService("dispdrv", true) - ->GetSurfaceFlinger(); R_ASSERT(system.ServiceManager() .GetService("vi:m", true) ->GetDisplayService(&m_display_service, VI::Policy::Compositor)); + R_ASSERT(m_display_service->GetManagerDisplayService(&m_manager_display_service)); m_process = process; m_system_shared_buffer_id = 0; @@ -37,46 +36,47 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro } void DisplayLayerManager::Finalize() { - if (!m_surface_flinger) { + if (!m_manager_display_service) { return; } // Clean up managed 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) { - m_surface_flinger->DestroyLayer(layer); + m_manager_display_service->DestroyManagedLayer(layer); } // Clean up shared layers. 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 // 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(); } -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 // 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. // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse // 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() { @@ -102,19 +93,19 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() { R_SUCCEED_IF(m_buffer_sharing_enabled); // 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); // 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. 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(); } @@ -135,13 +126,13 @@ void DisplayLayerManager::SetWindowVisibility(bool visible) { m_visible = visible; - if (m_surface_flinger) { + if (m_manager_display_service) { 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) { - 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, s32* out_fbshare_layer_index) { 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)); } diff --git a/src/core/hle/service/am/display_layer_manager.h b/src/core/hle/service/am/display_layer_manager.h index 7591b0e60..a66509c04 100644 --- a/src/core/hle/service/am/display_layer_manager.h +++ b/src/core/hle/service/am/display_layer_manager.h @@ -17,13 +17,10 @@ namespace Kernel { class KProcess; } -namespace Service::Nvnflinger { -class Nvnflinger; -} - namespace Service::VI { class IApplicationDisplayService; -} +class IManagerDisplayService; +} // namespace Service::VI namespace Service::AM { @@ -36,8 +33,8 @@ public: LibraryAppletMode mode); 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 GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, @@ -50,8 +47,8 @@ public: private: Kernel::KProcess* m_process{}; - std::shared_ptr m_surface_flinger{}; std::shared_ptr m_display_service{}; + std::shared_ptr m_manager_display_service{}; std::set m_managed_display_layers{}; std::set m_managed_display_recording_layers{}; u64 m_system_shared_buffer_id{}; diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 154c38951..b76f81e59 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -10,13 +10,11 @@ #include #include #include -#include #include "common/common_types.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" -#include "core/hle/service/nvnflinger/ui/fence.h" #include "core/hle/service/service.h" namespace Core { @@ -27,10 +25,6 @@ namespace Kernel { class KEvent; } -namespace Service::Nvnflinger { -class Nvnflinger; -} - namespace Service::Nvidia { namespace NvCore { @@ -99,7 +93,6 @@ public: private: friend class EventInterface; - friend class Service::Nvnflinger::Nvnflinger; /// Manages syncpoints on the host NvCore::Container container; diff --git a/src/core/hle/service/nvnflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h index 179938192..124accb94 100644 --- a/src/core/hle/service/nvnflinger/binder.h +++ b/src/core/hle/service/nvnflinger/binder.h @@ -20,29 +20,12 @@ class HLERequestContext; 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 { public: virtual ~IBinder() = default; - virtual void Transact(android::TransactionId code, u32 flags, std::span parcel_data, - std::span parcel_reply) = 0; - virtual Kernel::KReadableEvent& GetNativeHandle() = 0; + virtual void Transact(u32 code, std::span parcel_data, std::span parcel_reply, + u32 flags) = 0; + virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0; }; } // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp index cf151ea3a..123507123 100644 --- a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp @@ -12,7 +12,7 @@ namespace Service::android { -BufferItemConsumer::BufferItemConsumer(std::unique_ptr consumer_) +BufferItemConsumer::BufferItemConsumer(std::shared_ptr consumer_) : ConsumerBase{std::move(consumer_)} {} Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.h b/src/core/hle/service/nvnflinger/buffer_item_consumer.h index e0c6b3604..9f95c9280 100644 --- a/src/core/hle/service/nvnflinger/buffer_item_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.h @@ -19,7 +19,7 @@ class BufferItem; class BufferItemConsumer final : public ConsumerBase { public: - explicit BufferItemConsumer(std::unique_ptr consumer); + explicit BufferItemConsumer(std::shared_ptr consumer); Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, bool wait_for_fence = true); Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence); diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp index bbe8e06d4..3bc23aa97 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp @@ -4,12 +4,13 @@ // 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 +#include "common/assert.h" #include "common/logging/log.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_core.h" +#include "core/hle/service/nvnflinger/parcel.h" #include "core/hle/service/nvnflinger/producer_listener.h" -#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" namespace Service::android { @@ -254,4 +255,77 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { return Status::NoError; } +void BufferQueueConsumer::Transact(u32 code, std::span parcel_data, + std::span 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(code)) { + case TransactionId::AcquireBuffer: { + BufferItem item; + const s64 present_when = parcel_in.Read(); + + status = AcquireBuffer(&item, std::chrono::nanoseconds{present_when}); + + // TODO: can't write this directly, needs a flattener for the sp + // parcel_out.WriteFlattened(item); + UNREACHABLE(); + } + case TransactionId::ReleaseBuffer: { + const s32 slot = parcel_in.Read(); + const u64 frame_number = parcel_in.Read(); + const auto release_fence = parcel_in.ReadFlattened(); + + 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 diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h index 0a61e8dbd..a9226f1c3 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h @@ -10,6 +10,7 @@ #include #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/status.h" @@ -19,10 +20,10 @@ class BufferItem; class BufferQueueCore; class IConsumerListener; -class BufferQueueConsumer final { +class BufferQueueConsumer final : public IBinder { public: explicit BufferQueueConsumer(std::shared_ptr core_); - ~BufferQueueConsumer(); + ~BufferQueueConsumer() override; Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); @@ -30,6 +31,11 @@ public: Status Disconnect(); Status GetReleasedBuffers(u64* out_slot_mask); + void Transact(u32 code, std::span parcel_data, std::span parcel_reply, + u32 flags) override; + + Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; + private: std::shared_ptr core; BufferQueueDefs::SlotsType& slots; diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp index ec83beb9b..9e5091eeb 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp @@ -6,12 +6,9 @@ #include "common/assert.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_readable_event.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/nvnflinger/buffer_queue_core.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/ui/graphic_buffer.h" #include "core/hle/service/nvnflinger/window.h" -#include "core/hle/service/vi/vi.h" namespace Service::android { @@ -807,13 +803,31 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, return Status::NoError; } -void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span parcel_data, - std::span parcel_reply) { +void BufferQueueProducer::Transact(u32 code, std::span parcel_data, + std::span 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}; InputParcel parcel_in{parcel_data}; OutputParcel parcel_out{}; - switch (code) { + switch (static_cast(code)) { case TransactionId::Connect: { const auto enable_listener = parcel_in.Read(); const auto api = parcel_in.Read(); @@ -923,8 +937,8 @@ void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::spanGetReadableEvent(); +Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) { + return &buffer_wait_event->GetReadableEvent(); } } // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h index 4682b0f84..048523514 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h @@ -45,12 +45,12 @@ public: explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, std::shared_ptr buffer_queue_core_, Service::Nvidia::NvCore::NvMap& nvmap_); - ~BufferQueueProducer(); + ~BufferQueueProducer() override; - void Transact(android::TransactionId code, u32 flags, std::span parcel_data, - std::span parcel_reply) override; + void Transact(u32 code, std::span parcel_data, std::span parcel_reply, + u32 flags) override; - Kernel::KReadableEvent& GetNativeHandle() override; + Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; public: Status RequestBuffer(s32 slot, std::shared_ptr* buf); diff --git a/src/core/hle/service/nvnflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp index 1059e72bf..e360ebfd8 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.cpp +++ b/src/core/hle/service/nvnflinger/consumer_base.cpp @@ -14,7 +14,7 @@ namespace Service::android { -ConsumerBase::ConsumerBase(std::unique_ptr consumer_) +ConsumerBase::ConsumerBase(std::shared_ptr consumer_) : consumer{std::move(consumer_)} {} ConsumerBase::~ConsumerBase() { diff --git a/src/core/hle/service/nvnflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h index ea3e9e97a..b29c16f86 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.h +++ b/src/core/hle/service/nvnflinger/consumer_base.h @@ -27,7 +27,7 @@ public: void Abandon(); protected: - explicit ConsumerBase(std::unique_ptr consumer_); + explicit ConsumerBase(std::shared_ptr consumer_); ~ConsumerBase() override; void OnFrameAvailable(const BufferItem& item) override; @@ -54,7 +54,7 @@ protected: bool is_abandoned{}; - std::unique_ptr consumer; + std::shared_ptr consumer; mutable std::mutex mutex; }; diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h new file mode 100644 index 000000000..8a1956fe0 --- /dev/null +++ b/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 + +#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 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 buffer_item_consumer; + s32 consumer_id; + LayerBlending blending; + bool visible; +}; + +struct LayerStack { + std::list 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 diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index be7eb97a3..02215a786 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/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/hwc_layer.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 { @@ -44,7 +42,7 @@ s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) { 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) { boost::container::small_vector composition_stack; @@ -56,12 +54,11 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, bool has_acquired_buffer{}; // 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). - const auto result = this->CacheFramebufferLocked(layer, layer_id); + const auto result = this->CacheFramebufferLocked(layer, consumer_id); // If we failed, skip this layer. if (result == CacheStatus::NoBufferAvailable) { @@ -73,24 +70,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, 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& igbp_buffer = *item.graphic_buffer; // 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(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(item.transform), + .crop_rect = item.crop, + .acquire_fence = item.fence, + }); + } // We need to compose again either before this frame is supposed to // 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) { // TODO: support release fence // 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; } } @@ -146,26 +145,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, 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()) { return; } // 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) { - layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence()); + layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence()); } // Erase the slot. m_framebuffers.erase(it); } -bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) { +bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer) { // 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) { return false; } @@ -178,10 +177,10 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer 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. - const auto it = m_framebuffers.find(layer_id); + const auto it = m_framebuffers.find(consumer_id); if (it != m_framebuffers.end()) { // If it's currently still acquired, we are done. if (it->second.is_acquired) { @@ -203,7 +202,7 @@ HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer if (this->TryAcquireFramebufferLocked(layer, framebuffer)) { // 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. return CacheStatus::BufferAcquired; diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h index 28392c512..c5b830468 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.h +++ b/src/core/hle/service/nvnflinger/hardware_composer.h @@ -3,35 +3,29 @@ #pragma once -#include #include #include "core/hle/service/nvnflinger/buffer_item.h" +#include "core/hle/service/nvnflinger/display.h" namespace Service::Nvidia::Devices { class nvdisp_disp0; } -namespace Service::VI { -class Display; -class Layer; -} // namespace Service::VI - namespace Service::Nvnflinger { -using LayerId = u64; +using ConsumerId = s32; class HardwareComposer { public: explicit HardwareComposer(); ~HardwareComposer(); - u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, + u32 ComposeLocked(f32* out_speed_scale, Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp); - void RemoveLayerLocked(VI::Display& display, LayerId layer_id); + void RemoveLayerLocked(Display& display, ConsumerId consumer_id); private: - // TODO: do we want to track frame number in vi instead? u64 m_frame_number{0}; private: @@ -49,11 +43,11 @@ private: CachedBufferReused, }; - boost::container::flat_map m_framebuffers{}; + boost::container::flat_map m_framebuffers{}; 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 diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp index e09d72047..8629a2e89 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp @@ -10,7 +10,7 @@ namespace Service::Nvnflinger { IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, std::shared_ptr server, - std::shared_ptr surface_flinger) + std::shared_ptr surface_flinger) : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server), m_surface_flinger(surface_flinger) { static const FunctionInfo functions[] = { @@ -24,13 +24,18 @@ IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, IHOSBinderDriver::~IHOSBinderDriver() = default; -Result IHOSBinderDriver::TransactParcel(s32 binder_id, android::TransactionId transaction_id, +Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id, InBuffer parcel_data, OutBuffer parcel_reply, u32 flags) { LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id, 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(); } @@ -42,11 +47,16 @@ Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) { Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id, OutCopyHandle out_handle) { 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(); } -Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, +Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, u32 transaction_id, InBuffer parcel_data, OutBuffer parcel_reply, u32 flags) { diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver.h b/src/core/hle/service/nvnflinger/hos_binder_driver.h index aa9e3121a..b7fb07bd2 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver.h +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.h @@ -2,38 +2,45 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/cmif_types.h" -#include "core/hle/service/nvnflinger/binder.h" #include "core/hle/service/service.h" +namespace Kernel { +class KReadableEvent; +} + namespace Service::Nvnflinger { class HosBinderDriverServer; -class Nvnflinger; +class SurfaceFlinger; class IHOSBinderDriver final : public ServiceFramework { public: explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr server, - std::shared_ptr surface_flinger); + std::shared_ptr surface_flinger); ~IHOSBinderDriver() override; - std::shared_ptr GetSurfaceFlinger() { + std::shared_ptr GetSurfaceFlinger() { return m_surface_flinger; } + std::shared_ptr GetServer() { + return m_server; + } + private: - Result TransactParcel(s32 binder_id, android::TransactionId transaction_id, + Result TransactParcel(s32 binder_id, u32 transaction_id, InBuffer parcel_data, OutBuffer parcel_reply, u32 flags); Result AdjustRefcount(s32 binder_id, s32 addval, s32 type); Result GetNativeHandle(s32 binder_id, u32 type_id, OutCopyHandle out_handle); - Result TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, + Result TransactParcelAuto(s32 binder_id, u32 transaction_id, InBuffer parcel_data, OutBuffer parcel_reply, u32 flags); private: const std::shared_ptr m_server; - const std::shared_ptr m_surface_flinger; + const std::shared_ptr m_surface_flinger; }; } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp index b86a79ec9..29addda44 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp @@ -8,26 +8,30 @@ 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&& binder) { +s32 HosBinderDriverServer::RegisterBinder(std::shared_ptr&& binder) { std::scoped_lock lk{lock}; last_id++; - producers[last_id] = std::move(binder); + binders[last_id] = std::move(binder); 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 HosBinderDriverServer::TryGetBinder(s32 id) const { 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 {}; diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h index 58bb9469a..d72b50833 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h +++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h @@ -8,7 +8,6 @@ #include #include "common/common_types.h" -#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nvnflinger/binder.h" namespace Core { @@ -19,19 +18,18 @@ namespace Service::Nvnflinger { class HosBinderDriverServer final { public: - explicit HosBinderDriverServer(Core::System& system_); + explicit HosBinderDriverServer(); ~HosBinderDriverServer(); - u64 RegisterProducer(std::unique_ptr&& binder); + s32 RegisterBinder(std::shared_ptr&& binder); + void UnregisterBinder(s32 binder_id); - android::IBinder* TryGetProducer(u64 id); + std::shared_ptr TryGetBinder(s32 id) const; private: - KernelHelpers::ServiceContext service_context; - - std::unordered_map> producers; - std::mutex lock; - u64 last_id{}; + std::unordered_map> binders; + mutable std::mutex lock; + s32 last_id{}; }; } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index a20ef14af..9e3b68b8a 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -1,318 +1,19 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // 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_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_server.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/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 { -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(); - - nvdrv = system.ServiceManager().GetService("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 { - 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 { - 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 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 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 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(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(swap_interval); - return static_cast(speed_scale * (1000000000.f / effective_fps)); -} - void LoopProcess(Core::System& system) { - const auto binder_server = std::make_shared(system); - const auto surface_flinger = std::make_shared(system, *binder_server); + const auto binder_server = std::make_shared(); + const auto surface_flinger = std::make_shared(system, *binder_server); auto server_manager = std::make_unique(system); server_manager->RegisterNamedService( diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 941a98418..5c41f3013 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -3,158 +3,12 @@ #pragma once -#include -#include -#include -#include -#include - -#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 { -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 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 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 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 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 nvdrv; - s32 disp_fd; - - std::list 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 multi_composition_event; - std::shared_ptr single_composition_event; - - std::shared_ptr 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); } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp new file mode 100644 index 000000000..0e9714a03 --- /dev/null +++ b/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("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(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( + m_server.TryGetBinder(consumer_binder_id)); + + if (!display || !binder) { + return; + } + + auto buffer_item_consumer = std::make_shared(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(); + auto producer = std::make_shared(m_context, core, nvmap); + auto consumer = std::make_shared(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 diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h new file mode 100644 index 000000000..a2e661430 --- /dev/null +++ b/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 + +#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 m_displays; + std::shared_ptr nvdrv; + s32 disp_fd; + HardwareComposer m_composer; +}; + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 0718df981..ce5e3b5b4 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -7,67 +7,10 @@ #include "common/settings.h" #include "core/core.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/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" #include "core/reporter.h" namespace Service { @@ -208,73 +151,4 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, return result; } -/// Initialize Services -Services::Services(std::shared_ptr& 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 diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index cf4a3e8be..36aae1c79 100644 --- a/src/core/hle/service/service.h +++ b/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, Core::System& system); - ~Services(); -}; - } // namespace Service diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp new file mode 100644 index 000000000..d6c6eff50 --- /dev/null +++ b/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, 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 diff --git a/src/core/hle/service/services.h b/src/core/hle/service/services.h new file mode 100644 index 000000000..a99fa1e53 --- /dev/null +++ b/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, Core::System& system, + std::stop_token token); + ~Services(); +}; + +} // namespace Service diff --git a/src/core/hle/service/vi/application_display_service.cpp b/src/core/hle/service/vi/application_display_service.cpp index 9c009f902..6b0bcb536 100644 --- a/src/core/hle/service/vi/application_display_service.cpp +++ b/src/core/hle/service/vi/application_display_service.cpp @@ -3,23 +3,20 @@ #include "core/hle/service/cmif_serialization.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/os/event.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/system_display_service.h" #include "core/hle/service/vi/vi_results.h" namespace Service::VI { -IApplicationDisplayService::IApplicationDisplayService( - Core::System& system_, std::shared_ptr binder_service, - std::shared_ptr shared_buffer_manager) +IApplicationDisplayService::IApplicationDisplayService(Core::System& system_, + std::shared_ptr container) : 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 static const FunctionInfo functions[] = { {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"}, @@ -50,39 +47,41 @@ 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) { - m_surface_flinger->DestroyLayer(layer_id); + m_container->DestroyStrayLayer(layer_id); } } Result IApplicationDisplayService::GetRelayService( Out> out_relay_service) { 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( Out> out_system_display_service) { LOG_WARNING(Service_VI, "(STUBBED) called"); - *out_system_display_service = - std::make_shared(system, m_surface_flinger, m_shared_buffer_manager); + *out_system_display_service = std::make_shared(system, m_container); R_SUCCEED(); } Result IApplicationDisplayService::GetManagerDisplayService( Out> out_manager_display_service) { LOG_WARNING(Service_VI, "(STUBBED) called"); - *out_manager_display_service = - std::make_shared(system, m_surface_flinger); + *out_manager_display_service = std::make_shared(system, m_container); R_SUCCEED(); } Result IApplicationDisplayService::GetIndirectDisplayTransactionService( Out> out_indirect_display_transaction_service) { 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 out_display_id, DisplayName display_name) { @@ -92,14 +91,7 @@ Result IApplicationDisplayService::OpenDisplay(Out out_display_id, DisplayN ASSERT_MSG(strcmp(display_name.data(), "Default") == 0, "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 out_display_id) { @@ -109,8 +101,7 @@ Result IApplicationDisplayService::OpenDefaultDisplay(Out out_display_id) { Result IApplicationDisplayService::CloseDisplay(u64 display_id) { 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) { @@ -171,25 +162,19 @@ Result IApplicationDisplayService::OpenLayer(Out out_size, 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; - parcel.WriteInterface(NativeWindow{*buffer_queue_id}); + parcel.WriteInterface(NativeWindow{producer_binder_id}); const auto buffer = parcel.Serialize(); std::memcpy(out_native_window.data(), buffer.data(), @@ -202,12 +187,13 @@ Result IApplicationDisplayService::OpenLayer(Out out_size, Result IApplicationDisplayService::CloseLayer(u64 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( @@ -215,27 +201,19 @@ Result IApplicationDisplayService::CreateStrayLayer( u32 flags, u64 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; - parcel.WriteInterface(NativeWindow{*buffer_queue_id}); + parcel.WriteInterface(NativeWindow{producer_binder_id}); const auto buffer = parcel.Serialize(); std::memcpy(out_native_window.data(), buffer.data(), std::min(out_native_window.size(), buffer.size())); - *out_layer_id = *layer_id; *out_size = buffer.size(); R_SUCCEED(); @@ -243,25 +221,27 @@ Result IApplicationDisplayService::CreateStrayLayer( Result IApplicationDisplayService::DestroyStrayLayer(u64 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( OutCopyHandle out_vsync_event, u64 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(); } diff --git a/src/core/hle/service/vi/application_display_service.h b/src/core/hle/service/vi/application_display_service.h index 5022b2f63..1bdeb8f84 100644 --- a/src/core/hle/service/vi/application_display_service.h +++ b/src/core/hle/service/vi/application_display_service.h @@ -1,7 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + #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/vi/vi_types.h" @@ -10,28 +15,25 @@ class KReadableEvent; } namespace Service::Nvnflinger { -class Nvnflinger; class IHOSBinderDriver; -} // namespace Service::Nvnflinger +} namespace Service::VI { -class FbshareBufferManager; +class Container; class IManagerDisplayService; class ISystemDisplayService; class IApplicationDisplayService final : public ServiceFramework { public: - IApplicationDisplayService(Core::System& system_, - std::shared_ptr binder_service, - std::shared_ptr shared_buffer_manager); + IApplicationDisplayService(Core::System& system_, std::shared_ptr container); ~IApplicationDisplayService() override; - std::shared_ptr GetSharedBufferManager() const { - return m_shared_buffer_manager; + std::shared_ptr GetContainer() const { + return m_container; } -private: +public: Result GetRelayService(Out> out_relay_service); Result GetSystemDisplayService( Out> out_system_display_service); @@ -66,10 +68,13 @@ private: s64 width, s64 height); private: - const std::shared_ptr m_binder_service; - const std::shared_ptr m_surface_flinger; - const std::shared_ptr m_shared_buffer_manager; - std::vector m_stray_layer_ids; + const std::shared_ptr m_container; + + KernelHelpers::ServiceContext m_context; + std::mutex m_lock{}; + std::set m_open_layer_ids{}; + std::set m_stray_layer_ids{}; + std::map m_display_vsync_events{}; bool m_vsync_event_fetched{false}; }; diff --git a/src/core/hle/service/vi/application_root_service.cpp b/src/core/hle/service/vi/application_root_service.cpp index ed8c9b1b3..7f35a048d 100644 --- a/src/core/hle/service/vi/application_root_service.cpp +++ b/src/core/hle/service/vi/application_root_service.cpp @@ -4,17 +4,16 @@ #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/vi/application_display_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/vi.h" #include "core/hle/service/vi/vi_types.h" namespace Service::VI { -IApplicationRootService::IApplicationRootService( - Core::System& system_, std::shared_ptr binder_service, - std::shared_ptr 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) + : ServiceFramework{system_, "vi:u"}, m_container{std::move(container)} { static const FunctionInfo functions[] = { {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"}, {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -27,8 +26,8 @@ IApplicationRootService::~IApplicationRootService() = default; Result IApplicationRootService::GetDisplayService( Out> out_application_display_service, Policy policy) { 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 diff --git a/src/core/hle/service/vi/application_root_service.h b/src/core/hle/service/vi/application_root_service.h index 5970b6e68..15aa4483d 100644 --- a/src/core/hle/service/vi/application_root_service.h +++ b/src/core/hle/service/vi/application_root_service.h @@ -10,21 +10,15 @@ namespace Core { class System; } -namespace Service::Nvnflinger { -class IHOSBinderDriver; -} // namespace Service::Nvnflinger - namespace Service::VI { -class FbshareBufferManager; +class Container; class IApplicationDisplayService; enum class Policy : u32; class IApplicationRootService final : public ServiceFramework { public: - explicit IApplicationRootService(Core::System& system_, - std::shared_ptr binder_service, - std::shared_ptr shared_buffer_manager); + explicit IApplicationRootService(Core::System& system_, std::shared_ptr container); ~IApplicationRootService() override; private: @@ -33,8 +27,7 @@ private: Policy policy); private: - const std::shared_ptr m_binder_service; - const std::shared_ptr m_shared_buffer_manager; + const std::shared_ptr m_container; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/conductor.cpp b/src/core/hle/service/vi/conductor.cpp new file mode 100644 index 000000000..c8ce4fca0 --- /dev/null +++ b/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 { + 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 { + 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(m_swap_interval); + return static_cast(speed_scale * (1000000000.f / effective_fps)); +} + +} // namespace Service::VI diff --git a/src/core/hle/service/vi/conductor.h b/src/core/hle/service/vi/conductor.h new file mode 100644 index 000000000..52e3595d2 --- /dev/null +++ b/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 +#include + +#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 m_vsync_managers; + std::shared_ptr 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 diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp new file mode 100644 index 000000000..2d6b9cbfe --- /dev/null +++ b/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("dispdrv", true); + m_surface_flinger = m_binder_driver->GetSurfaceFlinger(); + + const auto nvdrv = + system.ServiceManager().GetService("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* out_binder_driver) { + *out_binder_driver = m_binder_driver; + R_SUCCEED(); +} + +Result Container::GetLayerProducerHandle( + std::shared_ptr* 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(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 diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h new file mode 100644 index 000000000..155c4c629 --- /dev/null +++ b/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 +#include +#include + +#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* out_binder_driver); + Result GetLayerProducerHandle(std::shared_ptr* 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 m_binder_driver{}; + std::shared_ptr m_surface_flinger{}; + std::optional m_shared_buffer_manager{}; + std::optional m_conductor{}; + bool m_is_shut_down{}; +}; + +} // namespace Service::VI diff --git a/src/core/hle/service/vi/display.h b/src/core/hle/service/vi/display.h new file mode 100644 index 000000000..fceda75e3 --- /dev/null +++ b/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 diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp deleted file mode 100644 index 7f2af9acc..000000000 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include - -#include - -#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 core; - std::unique_ptr producer; - std::unique_ptr consumer; -}; - -static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context, - Service::Nvidia::NvCore::NvMap& nvmap) { - auto buffer_queue_core = std::make_shared(); - return { - buffer_queue_core, - std::make_unique(service_context, buffer_queue_core, nvmap), - std::make_unique(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(); - 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(std::move(consumer)); - buffer_item_consumer->Connect(false); - - layers.emplace_back(std::make_unique(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) { - 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) { - return layer->GetLayerId() == layer_id; - }); - - if (itr == layers.end()) { - return nullptr; - } - - return itr->get(); -} - -} // namespace Service::VI diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h deleted file mode 100644 index 220292cff..000000000 --- a/src/core/hle/service/vi/display/vi_display.h +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include - -#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> layers; - std::unique_ptr hardware_composer; - Kernel::KEvent* vsync_event{}; - bool is_abandoned{}; -}; - -} // namespace Service::VI diff --git a/src/core/hle/service/vi/display_list.h b/src/core/hle/service/vi/display_list.h new file mode 100644 index 000000000..f710ac472 --- /dev/null +++ b/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 + +#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 + 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 m_displays{}; + u64 m_next_id{}; +}; + +} // namespace Service::VI diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.cpp b/src/core/hle/service/vi/fbshare_buffer_manager.cpp deleted file mode 100644 index e61c02e1c..000000000 --- a/src/core/hle/service/vi/fbshare_buffer_manager.cpp +++ /dev/null @@ -1,447 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -#include "core/core.h" -#include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_system_resource.h" -#include "core/hle/service/nvdrv/devices/nvmap.h" -#include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/nvnflinger/buffer_queue_producer.h" -#include "core/hle/service/nvnflinger/pixel_format.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/vi_results.h" -#include "video_core/gpu.h" -#include "video_core/host1x/host1x.h" - -namespace Service::VI { - -namespace { - -Result AllocateSharedBufferMemory(std::unique_ptr* out_page_group, - Core::System& system, u32 size) { - using Core::Memory::YUZU_PAGESIZE; - - // Allocate memory for the system shared buffer. - auto& kernel = system.Kernel(); - - // Hold a temporary page group reference while we try to map it. - auto pg = std::make_unique( - kernel, std::addressof(kernel.GetSystemSystemResource().GetBlockInfoManager())); - - // Allocate memory from secure pool. - R_TRY(kernel.MemoryManager().AllocateAndOpen( - pg.get(), size / YUZU_PAGESIZE, - Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure, - Kernel::KMemoryManager::Direction::FromBack))); - - // Fill the output data with red. - for (auto& block : *pg) { - u32* start = system.DeviceMemory().GetPointer(block.GetAddress()); - u32* end = system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); - - for (; start < end; start++) { - *start = 0xFF0000FF; - } - } - - // Return the mapped page group. - *out_page_group = std::move(pg); - - // We succeeded. - R_SUCCEED(); -} - -Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address, - std::unique_ptr& pg, - Kernel::KProcess* process, Core::System& system) { - using Core::Memory::YUZU_PAGESIZE; - - auto& page_table = process->GetPageTable(); - - // Get bounds of where mapping is possible. - const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart()); - const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE; - const auto state = Kernel::KMemoryState::IoMemory; - const auto perm = Kernel::KMemoryPermission::UserReadWrite; - std::mt19937_64 rng{process->GetRandomEntropy(0)}; - - // Retry up to 64 times to map into alias code range. - Result res = ResultSuccess; - int i; - for (i = 0; i < 64; i++) { - *out_map_address = alias_code_begin + ((rng() % alias_code_size) * YUZU_PAGESIZE); - res = page_table.MapPageGroup(*out_map_address, *pg, state, perm); - if (R_SUCCEEDED(res)) { - break; - } - } - - // Return failure, if necessary - R_UNLESS(i < 64, res); - - // We succeeded. - R_SUCCEED(); -} - -Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) { - // Create a handle. - Nvidia::Devices::nvmap::IocCreateParams create_params{ - .size = size, - .handle = 0, - }; - R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success, - VI::ResultOperationFailed); - - // Assign the output handle. - *out_nv_map_handle = create_params.handle; - - // We succeeded. - R_SUCCEED(); -} - -Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) { - // Free the handle. - Nvidia::Devices::nvmap::IocFreeParams free_params{ - .handle = handle, - }; - R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success, - VI::ResultOperationFailed); - - // We succeeded. - R_SUCCEED(); -} - -Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, - u32 size, Nvidia::DeviceFD nvmap_fd) { - // Assign the allocated memory to the handle. - Nvidia::Devices::nvmap::IocAllocParams alloc_params{ - .handle = handle, - .heap_mask = 0, - .flags = {}, - .align = 0, - .kind = 0, - .address = GetInteger(buffer), - }; - R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success, - VI::ResultOperationFailed); - - // We succeeded. - R_SUCCEED(); -} - -Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd, - Common::ProcessAddress buffer, u32 size) { - // Get the nvmap device. - auto nvmap = nvdrv.GetDevice(nvmap_fd); - ASSERT(nvmap != nullptr); - - // Create a handle. - R_TRY(CreateNvMapHandle(out_handle, *nvmap, size)); - - // Ensure we maintain a clean state on failure. - ON_RESULT_FAILURE { - R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)); - }; - - // Assign the allocated memory to the handle. - R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd)); -} - -void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) { - auto nvmap = nvdrv.GetDevice(nvmap_fd); - ASSERT(nvmap != nullptr); - - R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd)); -} - -constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; -constexpr u32 SharedBufferBlockLinearBpp = 4; - -constexpr u32 SharedBufferBlockLinearWidth = 1280; -constexpr u32 SharedBufferBlockLinearHeight = 768; -constexpr u32 SharedBufferBlockLinearStride = - SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp; -constexpr u32 SharedBufferNumSlots = 7; - -constexpr u32 SharedBufferWidth = 1280; -constexpr u32 SharedBufferHeight = 720; -constexpr u32 SharedBufferAsync = false; - -constexpr u32 SharedBufferSlotSize = - SharedBufferBlockLinearWidth * SharedBufferBlockLinearHeight * SharedBufferBlockLinearBpp; -constexpr u32 SharedBufferSize = SharedBufferSlotSize * SharedBufferNumSlots; - -constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] { - SharedMemoryPoolLayout layout{}; - layout.num_slots = SharedBufferNumSlots; - - for (u32 i = 0; i < SharedBufferNumSlots; i++) { - layout.slots[i].buffer_offset = i * SharedBufferSlotSize; - layout.slots[i].size = SharedBufferSlotSize; - layout.slots[i].width = SharedBufferWidth; - layout.slots[i].height = SharedBufferHeight; - } - - return layout; -}(); - -void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) { - auto buffer = std::make_shared(); - buffer->width = SharedBufferWidth; - buffer->height = SharedBufferHeight; - buffer->stride = SharedBufferBlockLinearStride; - buffer->format = SharedBufferBlockLinearFormat; - buffer->external_format = SharedBufferBlockLinearFormat; - buffer->buffer_id = handle; - buffer->offset = slot * SharedBufferSlotSize; - ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError); -} - -} // namespace - -FbshareBufferManager::FbshareBufferManager(Core::System& system, - std::shared_ptr surface_flinger, - std::shared_ptr nvdrv) - : m_system(system), m_surface_flinger(std::move(surface_flinger)), m_nvdrv(std::move(nvdrv)) {} - -FbshareBufferManager::~FbshareBufferManager() = default; - -Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, - u64* out_layer_handle, u64 display_id, - Nvnflinger::LayerBlending blending) { - std::scoped_lock lk{m_guard}; - - // Ensure we haven't already created. - const u64 aruid = owner_process->GetProcessId(); - R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied); - - // Allocate memory for the shared buffer if needed. - if (!m_buffer_page_group) { - R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system, - SharedBufferSize)); - - // Record buffer id. - m_buffer_id = m_next_buffer_id++; - - // Record display id. - m_display_id = display_id; - } - - // Map into process. - Common::ProcessAddress map_address{}; - R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group, - owner_process, m_system)); - - // Create new session. - auto [it, was_emplaced] = m_sessions.emplace(aruid, FbshareSession{}); - auto& session = it->second; - - auto& container = m_nvdrv->GetContainer(); - session.session_id = container.OpenSession(owner_process); - session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id); - - // Create an nvmap handle for the buffer and assign the memory to it. - R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv, - session.nvmap_fd, map_address, SharedBufferSize)); - - // 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); - - // Get the layer. - VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, session.layer_id); - ASSERT(layer != nullptr); - - // 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); - - // Assign outputs. - *out_buffer_id = m_buffer_id; - *out_layer_handle = session.layer_id; - - // We succeeded. - R_SUCCEED(); -} - -void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) { - std::scoped_lock lk{m_guard}; - - if (m_buffer_id == 0) { - return; - } - - const u64 aruid = owner_process->GetProcessId(); - const auto it = m_sessions.find(aruid); - if (it == m_sessions.end()) { - return; - } - - auto& session = it->second; - - // Destroy the layer. - m_surface_flinger->DestroyLayer(session.layer_id); - - // Close nvmap handle. - FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); - - // Close nvmap device. - m_nvdrv->Close(session.nvmap_fd); - - // Close session. - auto& container = m_nvdrv->GetContainer(); - container.CloseSession(session.session_id); - - // Erase. - 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) { - std::scoped_lock lk{m_guard}; - - R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); - R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound); - R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound); - - *out_pool_layout = SharedBufferPoolLayout; - *out_buffer_size = SharedBufferSize; - *out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle; - - 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& out_slot_indexes, - s64* out_target_slot, u64 layer_id) { - std::scoped_lock lk{m_guard}; - - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); - - // Get the producer. - auto& producer = layer->GetBufferQueue(); - - // Get the next buffer from the producer. - s32 slot; - R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, - SharedBufferWidth, SharedBufferHeight, - SharedBufferBlockLinearFormat, 0) == android::Status::NoError, - VI::ResultOperationFailed); - - // Assign remaining outputs. - *out_target_slot = slot; - out_slot_indexes = {0, 1, -1, -1}; - - // We succeeded. - R_SUCCEED(); -} - -Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence, - Common::Rectangle crop_region, - u32 transform, s32 swap_interval, - u64 layer_id, s64 slot) { - std::scoped_lock lk{m_guard}; - - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); - - // Get the producer. - auto& producer = layer->GetBufferQueue(); - - // Request to queue the buffer. - std::shared_ptr buffer; - R_UNLESS(producer.RequestBuffer(static_cast(slot), std::addressof(buffer)) == - android::Status::NoError, - VI::ResultOperationFailed); - - ON_RESULT_FAILURE { - producer.CancelBuffer(static_cast(slot), fence); - }; - - // Queue the buffer to the producer. - android::QueueBufferInput input{}; - android::QueueBufferOutput output{}; - input.crop = crop_region; - input.fence = fence; - input.transform = static_cast(transform); - input.swap_interval = swap_interval; - R_UNLESS(producer.QueueBuffer(static_cast(slot), input, std::addressof(output)) == - android::Status::NoError, - VI::ResultOperationFailed); - - // We succeeded. - R_SUCCEED(); -} - -Result FbshareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, - u64 layer_id) { - std::scoped_lock lk{m_guard}; - - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); - - // Get the producer. - auto& producer = layer->GetBufferQueue(); - - // Set the event. - *out_event = std::addressof(producer.GetNativeHandle()); - - // We succeeded. - R_SUCCEED(); -} - -Result FbshareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { - std::vector capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); - Common::ScratchBuffer scratch; - - // TODO: this could be optimized - s64 e = -1280 * 768 * 4; - for (auto& block : *m_buffer_page_group) { - u8* start = m_system.DeviceMemory().GetPointer(block.GetAddress()); - u8* end = m_system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); - - for (; start < end; start++) { - *start = 0; - - if (e >= 0 && e < static_cast(capture_buffer.size())) { - *start = capture_buffer[e]; - } - e++; - } - - m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) { - m_system.GPU().InvalidateRegion(addr, end - start); - }); - } - - *out_was_written = true; - *out_layer_index = 1; - R_SUCCEED(); -} - -} // namespace Service::VI diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.h b/src/core/hle/service/vi/fbshare_buffer_manager.h deleted file mode 100644 index b9e99e61f..000000000 --- a/src/core/hle/service/vi/fbshare_buffer_manager.h +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/math_util.h" -#include "core/hle/service/nvdrv/core/container.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/ui/fence.h" - -namespace Kernel { -class KPageGroup; -} - -namespace Service::VI { - -struct SharedMemorySlot { - u64 buffer_offset; - u64 size; - s32 width; - s32 height; -}; -static_assert(sizeof(SharedMemorySlot) == 0x18, "SharedMemorySlot has wrong size"); - -struct SharedMemoryPoolLayout { - s32 num_slots; - std::array slots; -}; -static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); - -struct FbshareSession; - -class FbshareBufferManager final { -public: - explicit FbshareBufferManager(Core::System& system, - std::shared_ptr surface_flinger, - std::shared_ptr nvdrv); - ~FbshareBufferManager(); - - 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 GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, - SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, - u64 applet_resource_user_id); - Result AcquireSharedFrameBuffer(android::Fence* out_fence, std::array& out_slots, - s64* out_target_slot, u64 layer_id); - Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle crop_region, - u32 transform, s32 swap_interval, u64 layer_id, s64 slot); - Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); - - Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); - -private: - Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id); - -private: - u64 m_next_buffer_id = 1; - u64 m_display_id = 0; - u64 m_buffer_id = 0; - SharedMemoryPoolLayout m_pool_layout = {}; - std::map m_sessions; - std::unique_ptr m_buffer_page_group; - - std::mutex m_guard; - Core::System& m_system; - const std::shared_ptr m_surface_flinger; - const std::shared_ptr m_nvdrv; -}; - -struct FbshareSession { - Nvidia::DeviceFD nvmap_fd = {}; - Nvidia::NvCore::SessionId session_id = {}; - u64 layer_id = {}; - u32 buffer_nvmap_handle = 0; -}; - -} // namespace Service::VI diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h new file mode 100644 index 000000000..b85c8df61 --- /dev/null +++ b/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 diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp deleted file mode 100644 index eca35d82a..000000000 --- a/src/core/hle/service/vi/layer/vi_layer.cpp +++ /dev/null @@ -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&& 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 diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h deleted file mode 100644 index 14e229903..000000000 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#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&& 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 consumer; - Service::Nvnflinger::LayerBlending blending; - bool open; - bool visible; -}; - -} // namespace Service::VI diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h new file mode 100644 index 000000000..1738ede9a --- /dev/null +++ b/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 + 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 m_layers{}; + u64 m_next_id{}; +}; + +} // namespace Service::VI diff --git a/src/core/hle/service/vi/manager_display_service.cpp b/src/core/hle/service/vi/manager_display_service.cpp index 22454ba61..9f856282e 100644 --- a/src/core/hle/service/vi/manager_display_service.cpp +++ b/src/core/hle/service/vi/manager_display_service.cpp @@ -2,23 +2,21 @@ // SPDX-License-Identifier: GPL-2.0-or-later #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/vi_results.h" namespace Service::VI { -IManagerDisplayService::IManagerDisplayService( - Core::System& system_, std::shared_ptr surface_flinger) - : ServiceFramework{system_, "IManagerDisplayService"}, - m_surface_flinger{std::move(surface_flinger)} { +IManagerDisplayService::IManagerDisplayService(Core::System& system_, + std::shared_ptr container) + : ServiceFramework{system_, "IManagerDisplayService"}, m_container{std::move(container)} { // clang-format off static const FunctionInfo functions[] = { {200, nullptr, "AllocateProcessHeapBlock"}, {201, nullptr, "FreeProcessHeapBlock"}, {1102, nullptr, "GetDisplayResolution"}, {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"}, - {2011, nullptr, "DestroyManagedLayer"}, + {2011, C<&IManagerDisplayService::DestroyManagedLayer>, "DestroyManagedLayer"}, {2012, nullptr, "CreateStrayLayer"}, {2050, nullptr, "CreateIndirectLayer"}, {2051, nullptr, "DestroyIndirectLayer"}, @@ -103,19 +101,30 @@ IManagerDisplayService::IManagerDisplayService( IManagerDisplayService::~IManagerDisplayService() = default; -Result IManagerDisplayService::CreateManagedLayer(Out 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 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) { @@ -124,8 +133,8 @@ Result IManagerDisplayService::AddToLayerStack(u32 stack_id, 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 diff --git a/src/core/hle/service/vi/manager_display_service.h b/src/core/hle/service/vi/manager_display_service.h index 4a3d53ff8..b1bdf7f41 100644 --- a/src/core/hle/service/vi/manager_display_service.h +++ b/src/core/hle/service/vi/manager_display_service.h @@ -4,22 +4,34 @@ #include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" +namespace Kernel { +class KProcess; +} + namespace Service::VI { +class Container; + class IManagerDisplayService final : public ServiceFramework { public: - explicit IManagerDisplayService(Core::System& system_, - std::shared_ptr surface_flinger); + explicit IManagerDisplayService(Core::System& system_, std::shared_ptr container); ~IManagerDisplayService() override; -private: - Result CreateManagedLayer(Out 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 out_layer_id, u32 flags, u64 display_id, AppletResourceUserId aruid); + Result DestroyManagedLayer(u64 layer_id); Result AddToLayerStack(u32 stack_id, u64 layer_id); Result SetLayerVisibility(bool visible, u64 layer_id); private: - const std::shared_ptr m_surface_flinger; + const std::shared_ptr m_container; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/manager_root_service.cpp b/src/core/hle/service/vi/manager_root_service.cpp index b61f0ecb6..0f16a15b4 100644 --- a/src/core/hle/service/vi/manager_root_service.cpp +++ b/src/core/hle/service/vi/manager_root_service.cpp @@ -4,6 +4,7 @@ #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/nvnflinger/hos_binder_driver.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/service_creator.h" #include "core/hle/service/vi/vi.h" @@ -11,11 +12,9 @@ namespace Service::VI { -IManagerRootService::IManagerRootService( - Core::System& system_, std::shared_ptr binder_service, - std::shared_ptr 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) + : ServiceFramework{system_, "vi:m"}, m_container{std::move(container)} { static const FunctionInfo functions[] = { {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -32,8 +31,8 @@ IManagerRootService::~IManagerRootService() = default; Result IManagerRootService::GetDisplayService( Out> out_application_display_service, Policy policy) { 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 diff --git a/src/core/hle/service/vi/manager_root_service.h b/src/core/hle/service/vi/manager_root_service.h index 509445b7b..77cd32869 100644 --- a/src/core/hle/service/vi/manager_root_service.h +++ b/src/core/hle/service/vi/manager_root_service.h @@ -10,21 +10,15 @@ namespace Core { class System; } -namespace Service::Nvnflinger { -class IHOSBinderDriver; -} // namespace Service::Nvnflinger - namespace Service::VI { -class FbshareBufferManager; +class Container; class IApplicationDisplayService; enum class Policy : u32; class IManagerRootService final : public ServiceFramework { public: - explicit IManagerRootService(Core::System& system_, - std::shared_ptr binder_service, - std::shared_ptr shared_buffer_manager); + explicit IManagerRootService(Core::System& system_, std::shared_ptr container); ~IManagerRootService() override; Result GetDisplayService( @@ -32,8 +26,7 @@ public: Policy policy); private: - const std::shared_ptr m_binder_service; - const std::shared_ptr m_shared_buffer_manager; + const std::shared_ptr m_container; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/service_creator.cpp b/src/core/hle/service/vi/service_creator.cpp index 414bd6655..2b8e5f957 100644 --- a/src/core/hle/service/vi/service_creator.cpp +++ b/src/core/hle/service/vi/service_creator.cpp @@ -22,8 +22,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { Result GetApplicationDisplayService( std::shared_ptr* out_application_display_service, - Core::System& system, std::shared_ptr binder_service, - std::shared_ptr shared_buffer_manager, Permission permission, + Core::System& system, std::shared_ptr container, Permission permission, Policy policy) { if (!IsValidServiceAccess(permission, policy)) { @@ -32,7 +31,7 @@ Result GetApplicationDisplayService( } *out_application_display_service = - std::make_shared(system, binder_service, shared_buffer_manager); + std::make_shared(system, std::move(container)); R_SUCCEED(); } diff --git a/src/core/hle/service/vi/service_creator.h b/src/core/hle/service/vi/service_creator.h index 6691f25c0..c6ba1797d 100644 --- a/src/core/hle/service/vi/service_creator.h +++ b/src/core/hle/service/vi/service_creator.h @@ -11,23 +11,18 @@ namespace Core { class System; } -namespace Service::Nvnflinger { -class IHOSBinderDriver; -} // namespace Service::Nvnflinger - union Result; namespace Service::VI { -class FbshareBufferManager; +class Container; class IApplicationDisplayService; enum class Permission; enum class Policy : u32; Result GetApplicationDisplayService( std::shared_ptr* out_application_display_service, - Core::System& system, std::shared_ptr binder_service, - std::shared_ptr shared_buffer_manager, Permission permission, + Core::System& system, std::shared_ptr container, Permission permission, Policy policy); } // namespace Service::VI diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp new file mode 100644 index 000000000..869b18961 --- /dev/null +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp @@ -0,0 +1,439 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_system_resource.h" +#include "core/hle/service/nvdrv/devices/nvmap.h" +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvnflinger/buffer_queue_producer.h" +#include "core/hle/service/nvnflinger/pixel_format.h" +#include "core/hle/service/nvnflinger/ui/graphic_buffer.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 "video_core/gpu.h" +#include "video_core/host1x/host1x.h" + +namespace Service::VI { + +namespace { + +Result AllocateSharedBufferMemory(std::unique_ptr* out_page_group, + Core::System& system, u32 size) { + using Core::Memory::YUZU_PAGESIZE; + + // Allocate memory for the system shared buffer. + auto& kernel = system.Kernel(); + + // Hold a temporary page group reference while we try to map it. + auto pg = std::make_unique( + kernel, std::addressof(kernel.GetSystemSystemResource().GetBlockInfoManager())); + + // Allocate memory from secure pool. + R_TRY(kernel.MemoryManager().AllocateAndOpen( + pg.get(), size / YUZU_PAGESIZE, + Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure, + Kernel::KMemoryManager::Direction::FromBack))); + + // Fill the output data with red. + for (auto& block : *pg) { + u32* start = system.DeviceMemory().GetPointer(block.GetAddress()); + u32* end = system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); + + for (; start < end; start++) { + *start = 0xFF0000FF; + } + } + + // Return the mapped page group. + *out_page_group = std::move(pg); + + // We succeeded. + R_SUCCEED(); +} + +Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address, + std::unique_ptr& pg, + Kernel::KProcess* process, Core::System& system) { + using Core::Memory::YUZU_PAGESIZE; + + auto& page_table = process->GetPageTable(); + + // Get bounds of where mapping is possible. + const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart()); + const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE; + const auto state = Kernel::KMemoryState::IoMemory; + const auto perm = Kernel::KMemoryPermission::UserReadWrite; + std::mt19937_64 rng{process->GetRandomEntropy(0)}; + + // Retry up to 64 times to map into alias code range. + Result res = ResultSuccess; + int i; + for (i = 0; i < 64; i++) { + *out_map_address = alias_code_begin + ((rng() % alias_code_size) * YUZU_PAGESIZE); + res = page_table.MapPageGroup(*out_map_address, *pg, state, perm); + if (R_SUCCEEDED(res)) { + break; + } + } + + // Return failure, if necessary + R_UNLESS(i < 64, res); + + // We succeeded. + R_SUCCEED(); +} + +Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) { + // Create a handle. + Nvidia::Devices::nvmap::IocCreateParams create_params{ + .size = size, + .handle = 0, + }; + R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success, + VI::ResultOperationFailed); + + // Assign the output handle. + *out_nv_map_handle = create_params.handle; + + // We succeeded. + R_SUCCEED(); +} + +Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) { + // Free the handle. + Nvidia::Devices::nvmap::IocFreeParams free_params{ + .handle = handle, + }; + R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success, + VI::ResultOperationFailed); + + // We succeeded. + R_SUCCEED(); +} + +Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, + u32 size, Nvidia::DeviceFD nvmap_fd) { + // Assign the allocated memory to the handle. + Nvidia::Devices::nvmap::IocAllocParams alloc_params{ + .handle = handle, + .heap_mask = 0, + .flags = {}, + .align = 0, + .kind = 0, + .address = GetInteger(buffer), + }; + R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success, + VI::ResultOperationFailed); + + // We succeeded. + R_SUCCEED(); +} + +Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd, + Common::ProcessAddress buffer, u32 size) { + // Get the nvmap device. + auto nvmap = nvdrv.GetDevice(nvmap_fd); + ASSERT(nvmap != nullptr); + + // Create a handle. + R_TRY(CreateNvMapHandle(out_handle, *nvmap, size)); + + // Ensure we maintain a clean state on failure. + ON_RESULT_FAILURE { + R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)); + }; + + // Assign the allocated memory to the handle. + R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd)); +} + +void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) { + auto nvmap = nvdrv.GetDevice(nvmap_fd); + ASSERT(nvmap != nullptr); + + R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd)); +} + +constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; +constexpr u32 SharedBufferBlockLinearBpp = 4; + +constexpr u32 SharedBufferBlockLinearWidth = 1280; +constexpr u32 SharedBufferBlockLinearHeight = 768; +constexpr u32 SharedBufferBlockLinearStride = + SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp; +constexpr u32 SharedBufferNumSlots = 7; + +constexpr u32 SharedBufferWidth = 1280; +constexpr u32 SharedBufferHeight = 720; +constexpr u32 SharedBufferAsync = false; + +constexpr u32 SharedBufferSlotSize = + SharedBufferBlockLinearWidth * SharedBufferBlockLinearHeight * SharedBufferBlockLinearBpp; +constexpr u32 SharedBufferSize = SharedBufferSlotSize * SharedBufferNumSlots; + +constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] { + SharedMemoryPoolLayout layout{}; + layout.num_slots = SharedBufferNumSlots; + + for (u32 i = 0; i < SharedBufferNumSlots; i++) { + layout.slots[i].buffer_offset = i * SharedBufferSlotSize; + layout.slots[i].size = SharedBufferSlotSize; + layout.slots[i].width = SharedBufferWidth; + layout.slots[i].height = SharedBufferHeight; + } + + return layout; +}(); + +void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) { + auto buffer = std::make_shared(); + buffer->width = SharedBufferWidth; + buffer->height = SharedBufferHeight; + buffer->stride = SharedBufferBlockLinearStride; + buffer->format = SharedBufferBlockLinearFormat; + buffer->external_format = SharedBufferBlockLinearFormat; + buffer->buffer_id = handle; + buffer->offset = slot * SharedBufferSlotSize; + ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError); +} + +} // namespace + +SharedBufferManager::SharedBufferManager(Core::System& system, Container& container, + std::shared_ptr nvdrv) + : m_system(system), m_container(container), m_nvdrv(std::move(nvdrv)) {} + +SharedBufferManager::~SharedBufferManager() = default; + +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}; + + // Ensure we haven't already created. + const u64 aruid = owner_process->GetProcessId(); + R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied); + + // Allocate memory for the shared buffer if needed. + if (!m_buffer_page_group) { + R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system, + SharedBufferSize)); + + // Record buffer id. + m_buffer_id = m_next_buffer_id++; + + // Record display id. + m_display_id = display_id; + } + + // Map into process. + Common::ProcessAddress map_address{}; + R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group, + owner_process, m_system)); + + // Create new session. + auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{}); + auto& session = it->second; + + auto& container = m_nvdrv->GetContainer(); + session.session_id = container.OpenSession(owner_process); + session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id); + + // Create an nvmap handle for the buffer and assign the memory to it. + R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv, + session.nvmap_fd, map_address, SharedBufferSize)); + + // Create and open a layer for the display. + s32 producer_binder_id; + R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id), + std::addressof(session.layer_id), display_id)); + + // Configure blending. + R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending)); + + // Get the producer and set preallocated buffers. + std::shared_ptr 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. + *out_buffer_id = m_buffer_id; + *out_layer_handle = session.layer_id; + + // We succeeded. + R_SUCCEED(); +} + +void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) { + std::scoped_lock lk{m_guard}; + + if (m_buffer_id == 0) { + return; + } + + const u64 aruid = owner_process->GetProcessId(); + const auto it = m_sessions.find(aruid); + if (it == m_sessions.end()) { + return; + } + + auto& session = it->second; + + // Destroy the layer. + R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); + + // Close nvmap handle. + FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); + + // Close nvmap device. + m_nvdrv->Close(session.nvmap_fd); + + // Close session. + auto& container = m_nvdrv->GetContainer(); + container.CloseSession(session.session_id); + + // Erase. + m_sessions.erase(it); +} + +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}; + + R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); + R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound); + R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound); + + *out_pool_layout = SharedBufferPoolLayout; + *out_buffer_size = SharedBufferSize; + *out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle; + + R_SUCCEED(); +} + +Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, + std::array& out_slot_indexes, + s64* out_target_slot, u64 layer_id) { + std::scoped_lock lk{m_guard}; + + // Get the producer. + std::shared_ptr producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); + + // Get the next buffer from the producer. + s32 slot; + R_UNLESS(producer->DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, + SharedBufferWidth, SharedBufferHeight, + SharedBufferBlockLinearFormat, 0) == android::Status::NoError, + VI::ResultOperationFailed); + + // Assign remaining outputs. + *out_target_slot = slot; + out_slot_indexes = {0, 1, -1, -1}; + + // We succeeded. + R_SUCCEED(); +} + +Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, + Common::Rectangle crop_region, + u32 transform, s32 swap_interval, u64 layer_id, + s64 slot) { + std::scoped_lock lk{m_guard}; + + // Get the producer. + std::shared_ptr producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); + + // Request to queue the buffer. + std::shared_ptr buffer; + R_UNLESS(producer->RequestBuffer(static_cast(slot), std::addressof(buffer)) == + android::Status::NoError, + VI::ResultOperationFailed); + + ON_RESULT_FAILURE { + producer->CancelBuffer(static_cast(slot), fence); + }; + + // Queue the buffer to the producer. + android::QueueBufferInput input{}; + android::QueueBufferOutput output{}; + input.crop = crop_region; + input.fence = fence; + input.transform = static_cast(transform); + input.swap_interval = swap_interval; + R_UNLESS(producer->QueueBuffer(static_cast(slot), input, std::addressof(output)) == + android::Status::NoError, + VI::ResultOperationFailed); + + // We succeeded. + R_SUCCEED(); +} + +Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { + std::scoped_lock lk{m_guard}; + + // Get the producer. + std::shared_ptr producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); + + // Cancel. + producer->CancelBuffer(static_cast(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. + std::shared_ptr producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); + + // Set the event. + *out_event = producer->GetNativeHandle({}); + + // We succeeded. + R_SUCCEED(); +} + +Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { + std::vector capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); + Common::ScratchBuffer scratch; + + // TODO: this could be optimized + s64 e = -1280 * 768 * 4; + for (auto& block : *m_buffer_page_group) { + u8* start = m_system.DeviceMemory().GetPointer(block.GetAddress()); + u8* end = m_system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); + + for (; start < end; start++) { + *start = 0; + + if (e >= 0 && e < static_cast(capture_buffer.size())) { + *start = capture_buffer[e]; + } + e++; + } + + m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) { + m_system.GPU().InvalidateRegion(addr, end - start); + }); + } + + *out_was_written = true; + *out_layer_index = 1; + R_SUCCEED(); +} + +} // namespace Service::VI diff --git a/src/core/hle/service/vi/shared_buffer_manager.h b/src/core/hle/service/vi/shared_buffer_manager.h new file mode 100644 index 000000000..7c9bb7199 --- /dev/null +++ b/src/core/hle/service/vi/shared_buffer_manager.h @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/math_util.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/nvdata.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" +#include "core/hle/service/nvnflinger/ui/fence.h" + +namespace Kernel { +class KPageGroup; +class KReadableEvent; +} // namespace Kernel + +namespace Service::android { +class BufferQueueProducer; +} + +namespace Service::Nvidia { +class Module; +} + +union Result; + +namespace Service::VI { + +class Container; + +struct SharedMemorySlot { + u64 buffer_offset; + u64 size; + s32 width; + s32 height; +}; +static_assert(sizeof(SharedMemorySlot) == 0x18, "SharedMemorySlot has wrong size"); + +struct SharedMemoryPoolLayout { + s32 num_slots; + std::array slots; +}; +static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); + +struct SharedBufferSession; + +class SharedBufferManager final { +public: + explicit SharedBufferManager(Core::System& system, Container& container, + std::shared_ptr nvdrv); + ~SharedBufferManager(); + + 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, + SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, + u64 applet_resource_user_id); + Result AcquireSharedFrameBuffer(android::Fence* out_fence, std::array& out_slots, + s64* out_target_slot, u64 layer_id); + Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle crop_region, + 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 WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); + +private: + u64 m_next_buffer_id = 1; + u64 m_display_id = 0; + u64 m_buffer_id = 0; + SharedMemoryPoolLayout m_pool_layout = {}; + std::map m_sessions; + std::unique_ptr m_buffer_page_group; + + std::mutex m_guard; + Core::System& m_system; + Container& m_container; + const std::shared_ptr m_nvdrv; +}; + +struct SharedBufferSession { + Nvidia::DeviceFD nvmap_fd = {}; + Nvidia::NvCore::SessionId session_id = {}; + u64 layer_id = {}; + u32 buffer_nvmap_handle = 0; +}; + +} // namespace Service::VI diff --git a/src/core/hle/service/vi/system_display_service.cpp b/src/core/hle/service/vi/system_display_service.cpp index 4670cf4cc..9e28fdda3 100644 --- a/src/core/hle/service/vi/system_display_service.cpp +++ b/src/core/hle/service/vi/system_display_service.cpp @@ -3,17 +3,15 @@ #include "common/settings.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/vi_types.h" namespace Service::VI { -ISystemDisplayService::ISystemDisplayService( - Core::System& system_, std::shared_ptr surface_flinger, - std::shared_ptr 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) + : ServiceFramework{system_, "ISystemDisplayService"}, m_container{std::move(container)} { // clang-format off static const FunctionInfo functions[] = { {1200, nullptr, "GetZOrderCountMin"}, @@ -61,7 +59,7 @@ ISystemDisplayService::ISystemDisplayService( {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"}, {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"}, {8257, nullptr, "FillSharedFrameBufferColor"}, - {8258, nullptr, "CancelSharedFrameBuffer"}, + {8258, C<&ISystemDisplayService::CancelSharedFrameBuffer>, "CancelSharedFrameBuffer"}, {9000, nullptr, "GetDp2hdmiController"}, }; // clang-format on @@ -106,7 +104,7 @@ Result ISystemDisplayService::GetSharedBufferMemoryHandleId( ClientAppletResourceUserId aruid) { 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)); } @@ -124,8 +122,8 @@ Result ISystemDisplayService::AcquireSharedFrameBuffer(Out out_f Out> out_slots, Out out_target_slot, u64 layer_id) { 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, @@ -133,14 +131,20 @@ Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence, u32 window_transform, s32 swap_interval, u64 layer_id, s64 surface_id) { 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)); } Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent( OutCopyHandle out_event, u64 layer_id) { 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 diff --git a/src/core/hle/service/vi/system_display_service.h b/src/core/hle/service/vi/system_display_service.h index b84c9725f..63c1a4dc5 100644 --- a/src/core/hle/service/vi/system_display_service.h +++ b/src/core/hle/service/vi/system_display_service.h @@ -5,21 +5,15 @@ #include "core/hle/service/cmif_types.h" #include "core/hle/service/nvnflinger/ui/fence.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 { -class FbshareBufferManager; +class Container; class ISystemDisplayService final : public ServiceFramework { public: - explicit ISystemDisplayService(Core::System& system_, - std::shared_ptr surface_flinger, - std::shared_ptr shared_buffer_manager); + explicit ISystemDisplayService(Core::System& system_, std::shared_ptr container); ~ISystemDisplayService() override; private: @@ -42,10 +36,10 @@ private: Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle crop_region, u32 window_transform, s32 swap_interval, u64 layer_id, s64 surface_id); + Result CancelSharedFrameBuffer(u64 layer_id, s64 slot); private: - const std::shared_ptr m_surface_flinger; - const std::shared_ptr m_shared_buffer_manager; + const std::shared_ptr m_container; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/system_root_service.cpp b/src/core/hle/service/vi/system_root_service.cpp index 2254ed111..3489727d8 100644 --- a/src/core/hle/service/vi/system_root_service.cpp +++ b/src/core/hle/service/vi/system_root_service.cpp @@ -3,6 +3,7 @@ #include "core/hle/service/cmif_serialization.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/system_root_service.h" #include "core/hle/service/vi/vi.h" @@ -10,11 +11,8 @@ namespace Service::VI { -ISystemRootService::ISystemRootService(Core::System& system_, - std::shared_ptr binder_service, - std::shared_ptr 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) + : ServiceFramework{system_, "vi:s"}, m_container{std::move(container)} { static const FunctionInfo functions[] = { {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -27,8 +25,8 @@ ISystemRootService::~ISystemRootService() = default; Result ISystemRootService::GetDisplayService( Out> out_application_display_service, Policy policy) { 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 diff --git a/src/core/hle/service/vi/system_root_service.h b/src/core/hle/service/vi/system_root_service.h index 16c997422..9d5aa53d3 100644 --- a/src/core/hle/service/vi/system_root_service.h +++ b/src/core/hle/service/vi/system_root_service.h @@ -10,21 +10,15 @@ namespace Core { class System; } -namespace Service::Nvnflinger { -class IHOSBinderDriver; -} // namespace Service::Nvnflinger - namespace Service::VI { -class FbshareBufferManager; +class Container; class IApplicationDisplayService; enum class Policy : u32; class ISystemRootService final : public ServiceFramework { public: - explicit ISystemRootService(Core::System& system_, - std::shared_ptr binder_service, - std::shared_ptr shared_buffer_manager); + explicit ISystemRootService(Core::System& system_, std::shared_ptr container); ~ISystemRootService() override; private: @@ -32,8 +26,7 @@ private: Out> out_application_display_service, Policy policy); - const std::shared_ptr m_binder_service; - const std::shared_ptr m_shared_buffer_manager; + const std::shared_ptr m_container; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index f361b9f4c..b388efaf6 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -2,38 +2,29 @@ // 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/hos_binder_driver.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/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/system_root_service.h" #include "core/hle/service/vi/vi.h" namespace Service::VI { -void LoopProcess(Core::System& system) { - const auto binder_service = - system.ServiceManager().GetService("dispdrv", true); - const auto nvdrv = - system.ServiceManager().GetService("nvdrv:s", true)->GetModule(); - const auto shared_buffer_manager = - std::make_shared(system, binder_service->GetSurfaceFlinger(), nvdrv); +void LoopProcess(Core::System& system, std::stop_token token) { + const auto container = std::make_shared(system); auto server_manager = std::make_unique(system); + server_manager->RegisterNamedService("vi:m", + std::make_shared(system, container)); + server_manager->RegisterNamedService("vi:s", + std::make_shared(system, container)); server_manager->RegisterNamedService( - "vi:m", - std::make_shared(system, binder_service, shared_buffer_manager)); - server_manager->RegisterNamedService( - "vi:s", - std::make_shared(system, binder_service, shared_buffer_manager)); - server_manager->RegisterNamedService( - "vi:u", - std::make_shared(system, binder_service, shared_buffer_manager)); + "vi:u", std::make_shared(system, container)); + + std::stop_callback cb(token, [=] { container->OnTerminate(); }); + ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 0c3dc175d..7c1f350d8 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -3,12 +3,14 @@ #pragma once +#include "common/polyfill_thread.h" + namespace Core { class System; } namespace Service::VI { -void LoopProcess(Core::System& system); +void LoopProcess(Core::System& system, std::stop_token token); } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_types.h b/src/core/hle/service/vi/vi_types.h index 91e4b380c..7f2c70aef 100644 --- a/src/core/hle/service/vi/vi_types.h +++ b/src/core/hle/service/vi/vi_types.h @@ -68,7 +68,7 @@ static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); class NativeWindow final { public: - constexpr explicit NativeWindow(u32 id_) : id{id_} {} + constexpr explicit NativeWindow(s32 id_) : id{static_cast(id_)} {} constexpr explicit NativeWindow(const NativeWindow& other) = default; private: diff --git a/src/core/hle/service/vi/vsync_manager.cpp b/src/core/hle/service/vi/vsync_manager.cpp new file mode 100644 index 000000000..bdc4dfa96 --- /dev/null +++ b/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 diff --git a/src/core/hle/service/vi/vsync_manager.h b/src/core/hle/service/vi/vsync_manager.h new file mode 100644 index 000000000..5d45bb5ee --- /dev/null +++ b/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 + +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 m_vsync_events; +}; + +} // namespace Service::VI -- cgit v1.2.3