diff options
Diffstat (limited to 'src/core/hle/service/vi')
33 files changed, 1086 insertions, 721 deletions
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<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager) +IApplicationDisplayService::IApplicationDisplayService(Core::System& system_, + std::shared_ptr<Container> 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<SharedPointer<Nvnflinger::IHOSBinderDriver>> 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<SharedPointer<ISystemDisplayService>> out_system_display_service) { LOG_WARNING(Service_VI, "(STUBBED) called"); - *out_system_display_service = - std::make_shared<ISystemDisplayService>(system, m_surface_flinger, m_shared_buffer_manager); + *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_container); R_SUCCEED(); } Result IApplicationDisplayService::GetManagerDisplayService( Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) { LOG_WARNING(Service_VI, "(STUBBED) called"); - *out_manager_display_service = - std::make_shared<IManagerDisplayService>(system, m_surface_flinger); + *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_container); R_SUCCEED(); } Result IApplicationDisplayService::GetIndirectDisplayTransactionService( Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> 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<u64> out_display_id, DisplayName display_name) { @@ -92,14 +91,7 @@ Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayN ASSERT_MSG(strcmp(display_name.data(), "Default") == 0, "Non-default displays aren't supported yet"); - const auto display_id = m_surface_flinger->OpenDisplay(display_name.data()); - if (!display_id) { - LOG_ERROR(Service_VI, "Display not found! display_name={}", display_name.data()); - R_THROW(VI::ResultNotFound); - } - - *out_display_id = *display_id; - R_SUCCEED(); + R_RETURN(m_container->OpenDisplay(out_display_id, display_name)); } Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) { @@ -109,8 +101,7 @@ Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> 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<u64> 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<u64> 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<Kernel::KReadableEvent> 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 <map> +#include <set> + #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<IApplicationDisplayService> { public: - IApplicationDisplayService(Core::System& system_, - std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager); + IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container); ~IApplicationDisplayService() override; - std::shared_ptr<FbshareBufferManager> GetSharedBufferManager() const { - return m_shared_buffer_manager; + std::shared_ptr<Container> GetContainer() const { + return m_container; } -private: +public: Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service); Result GetSystemDisplayService( Out<SharedPointer<ISystemDisplayService>> out_system_display_service); @@ -66,10 +68,13 @@ private: s64 width, s64 height); private: - const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; - const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger; - const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager; - std::vector<u64> m_stray_layer_ids; + const std::shared_ptr<Container> m_container; + + KernelHelpers::ServiceContext m_context; + std::mutex m_lock{}; + std::set<u64> m_open_layer_ids{}; + std::set<u64> m_stray_layer_ids{}; + std::map<u64, Event> m_display_vsync_events{}; bool m_vsync_event_fetched{false}; }; 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<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager) - : ServiceFramework{system_, "vi:u"}, m_binder_service{std::move(binder_service)}, - m_shared_buffer_manager{std::move(shared_buffer_manager)} { +IApplicationRootService::IApplicationRootService(Core::System& system_, + std::shared_ptr<Container> container) + : ServiceFramework{system_, "vi:u"}, m_container{std::move(container)} { static const FunctionInfo functions[] = { {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"}, {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -27,8 +26,8 @@ IApplicationRootService::~IApplicationRootService() = default; Result IApplicationRootService::GetDisplayService( Out<SharedPointer<IApplicationDisplayService>> 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<IApplicationRootService> { public: - explicit IApplicationRootService(Core::System& system_, - std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager); + explicit IApplicationRootService(Core::System& system_, std::shared_ptr<Container> container); ~IApplicationRootService() override; private: @@ -33,8 +27,7 @@ private: Policy policy); private: - const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; - const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager; + const std::shared_ptr<Container> m_container; }; } // namespace Service::VI 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<std::chrono::nanoseconds> { + m_signal.Set(); + return std::chrono::nanoseconds(this->GetNextTicks()); + }); + + system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event); + m_thread = std::jthread([this](std::stop_token token) { this->VsyncThread(token); }); + } else { + m_event = Core::Timing::CreateEvent( + "ScreenComposition", + [this](s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { + this->ProcessVsync(); + return std::chrono::nanoseconds(this->GetNextTicks()); + }); + + system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event); + } +} + +Conductor::~Conductor() { + m_system.CoreTiming().UnscheduleEvent(m_event); + + if (m_system.IsMulticore()) { + m_thread.request_stop(); + m_signal.Set(); + } +} + +void Conductor::LinkVsyncEvent(u64 display_id, Event* event) { + if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) { + it->second.LinkVsyncEvent(event); + } +} + +void Conductor::UnlinkVsyncEvent(u64 display_id, Event* event) { + if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) { + it->second.UnlinkVsyncEvent(event); + } +} + +void Conductor::ProcessVsync() { + for (auto& [display_id, manager] : m_vsync_managers) { + m_container.ComposeOnDisplay(&m_swap_interval, &m_compose_speed_scale, display_id); + manager.SignalVsync(); + } +} + +void Conductor::VsyncThread(std::stop_token token) { + Common::SetCurrentThreadName("VSyncThread"); + + while (!token.stop_requested()) { + m_signal.Wait(); + + if (m_system.IsShuttingDown()) { + return; + } + + this->ProcessVsync(); + } +} + +s64 Conductor::GetNextTicks() const { + const auto& settings = Settings::values; + auto speed_scale = 1.f; + if (settings.use_multi_core.GetValue()) { + if (settings.use_speed_limit.GetValue()) { + // Scales the speed based on speed_limit setting on MC. SC is handled by + // SpeedLimiter::DoSpeedLimiting. + speed_scale = 100.f / settings.speed_limit.GetValue(); + } else { + // Run at unlocked framerate. + speed_scale = 0.01f; + } + } + + // Adjust by speed limit determined during composition. + speed_scale /= m_compose_speed_scale; + + if (m_system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { + // Run at intended presentation rate during video playback. + speed_scale = 1.f; + } + + const f32 effective_fps = 60.f / static_cast<f32>(m_swap_interval); + return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); +} + +} // namespace Service::VI 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 <memory> +#include <unordered_map> + +#include "common/common_types.h" +#include "common/polyfill_thread.h" +#include "common/thread.h" + +namespace Core { +class System; +} + +namespace Core::Timing { +struct EventType; +} + +namespace Service { +class Event; +} + +namespace Service::VI { + +class Container; +class DisplayList; +class VsyncManager; + +class Conductor { +public: + explicit Conductor(Core::System& system, Container& container, DisplayList& displays); + ~Conductor(); + + void LinkVsyncEvent(u64 display_id, Event* event); + void UnlinkVsyncEvent(u64 display_id, Event* event); + +private: + void ProcessVsync(); + void VsyncThread(std::stop_token token); + s64 GetNextTicks() const; + +private: + Core::System& m_system; + Container& m_container; + std::unordered_map<u64, VsyncManager> m_vsync_managers; + std::shared_ptr<Core::Timing::EventType> m_event; + Common::Event m_signal; + std::jthread m_thread; + +private: + s32 m_swap_interval = 1; + f32 m_compose_speed_scale = 1.0f; +}; + +} // namespace Service::VI 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<Nvnflinger::IHOSBinderDriver>("dispdrv", true); + m_surface_flinger = m_binder_driver->GetSurfaceFlinger(); + + const auto nvdrv = + system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule(); + m_shared_buffer_manager.emplace(system, *this, nvdrv); + + m_displays.ForEachDisplay( + [&](auto& display) { m_surface_flinger->AddDisplay(display.GetId()); }); + + m_conductor.emplace(system, *this, m_displays); +} + +Container::~Container() { + this->OnTerminate(); +} + +void Container::OnTerminate() { + std::scoped_lock lk{m_lock}; + + m_is_shut_down = true; + + m_layers.ForEachLayer([&](auto& layer) { + if (layer.IsOpen()) { + this->DestroyBufferQueueLocked(&layer); + } + }); + + m_displays.ForEachDisplay( + [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); }); +} + +SharedBufferManager* Container::GetSharedBufferManager() { + return std::addressof(*m_shared_buffer_manager); +} + +Result Container::GetBinderDriver( + std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver) { + *out_binder_driver = m_binder_driver; + R_SUCCEED(); +} + +Result Container::GetLayerProducerHandle( + std::shared_ptr<android::BufferQueueProducer>* out_producer, u64 layer_id) { + std::scoped_lock lk{m_lock}; + + auto* const layer = m_layers.GetLayerById(layer_id); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + + const auto binder = m_binder_driver->GetServer()->TryGetBinder(layer->GetProducerBinderId()); + R_UNLESS(binder != nullptr, VI::ResultNotFound); + + *out_producer = std::static_pointer_cast<android::BufferQueueProducer>(binder); + R_SUCCEED(); +} + +Result Container::OpenDisplay(u64* out_display_id, const DisplayName& display_name) { + auto* const display = m_displays.GetDisplayByName(display_name); + R_UNLESS(display != nullptr, VI::ResultNotFound); + + *out_display_id = display->GetId(); + R_SUCCEED(); +} + +Result Container::CloseDisplay(u64 display_id) { + R_SUCCEED(); +} + +Result Container::CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid) { + std::scoped_lock lk{m_lock}; + R_RETURN(this->CreateLayerLocked(out_layer_id, display_id, owner_aruid)); +} + +Result Container::DestroyManagedLayer(u64 layer_id) { + std::scoped_lock lk{m_lock}; + + // Try to close, if open, but don't fail if not. + this->CloseLayerLocked(layer_id); + + R_RETURN(this->DestroyLayerLocked(layer_id)); +} + +Result Container::OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { + std::scoped_lock lk{m_lock}; + R_RETURN(this->OpenLayerLocked(out_producer_binder_id, layer_id, aruid)); +} + +Result Container::CloseLayer(u64 layer_id) { + std::scoped_lock lk{m_lock}; + R_RETURN(this->CloseLayerLocked(layer_id)); +} + +Result Container::SetLayerVisibility(u64 layer_id, bool visible) { + std::scoped_lock lk{m_lock}; + + auto* const layer = m_layers.GetLayerById(layer_id); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + + m_surface_flinger->SetLayerVisibility(layer->GetConsumerBinderId(), visible); + R_SUCCEED(); +} + +Result Container::SetLayerBlending(u64 layer_id, bool enabled) { + std::scoped_lock lk{m_lock}; + + auto* const layer = m_layers.GetLayerById(layer_id); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + + m_surface_flinger->SetLayerBlending(layer->GetConsumerBinderId(), + enabled ? Nvnflinger::LayerBlending::Coverage + : Nvnflinger::LayerBlending::None); + R_SUCCEED(); +} + +void Container::LinkVsyncEvent(u64 display_id, Event* event) { + std::scoped_lock lk{m_lock}; + m_conductor->LinkVsyncEvent(display_id, event); +} + +void Container::UnlinkVsyncEvent(u64 display_id, Event* event) { + std::scoped_lock lk{m_lock}; + m_conductor->UnlinkVsyncEvent(display_id, event); +} + +Result Container::CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id) { + std::scoped_lock lk{m_lock}; + R_TRY(this->CreateLayerLocked(out_layer_id, display_id, {})); + R_RETURN(this->OpenLayerLocked(out_producer_binder_id, *out_layer_id, {})); +} + +Result Container::DestroyStrayLayer(u64 layer_id) { + std::scoped_lock lk{m_lock}; + R_TRY(this->CloseLayerLocked(layer_id)); + R_RETURN(this->DestroyLayerLocked(layer_id)); +} + +Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid) { + auto* const display = m_displays.GetDisplayById(display_id); + R_UNLESS(display != nullptr, VI::ResultNotFound); + + auto* const layer = m_layers.CreateLayer(owner_aruid, display); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + + *out_layer_id = layer->GetId(); + R_SUCCEED(); +} + +Result Container::DestroyLayerLocked(u64 layer_id) { + R_SUCCEED_IF(m_layers.DestroyLayer(layer_id)); + R_THROW(VI::ResultNotFound); +} + +Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { + R_UNLESS(!m_is_shut_down, VI::ResultOperationFailed); + + auto* const layer = m_layers.GetLayerById(layer_id); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed); + R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied); + + this->CreateBufferQueueLocked(layer); + *out_producer_binder_id = layer->GetProducerBinderId(); + + R_SUCCEED(); +} + +Result Container::CloseLayerLocked(u64 layer_id) { + auto* const layer = m_layers.GetLayerById(layer_id); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed); + + this->DestroyBufferQueueLocked(layer); + + R_SUCCEED(); +} + +void Container::CreateBufferQueueLocked(Layer* layer) { + s32 consumer_binder_id, producer_binder_id; + m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id); + layer->Open(consumer_binder_id, producer_binder_id); + + if (auto* display = layer->GetDisplay(); display != nullptr) { + m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id); + } +} + +void Container::DestroyBufferQueueLocked(Layer* layer) { + if (auto* display = layer->GetDisplay(); display != nullptr) { + m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(), + layer->GetConsumerBinderId()); + } + + layer->Close(); + m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(), + layer->GetProducerBinderId()); +} + +void Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, + u64 display_id) { + std::scoped_lock lk{m_lock}; + m_surface_flinger->ComposeDisplay(out_swap_interval, out_compose_speed_scale, display_id); +} + +} // namespace Service::VI 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 <memory> +#include <mutex> +#include <optional> + +#include "core/hle/service/vi/conductor.h" +#include "core/hle/service/vi/display_list.h" +#include "core/hle/service/vi/layer_list.h" +#include "core/hle/service/vi/shared_buffer_manager.h" + +union Result; + +namespace Service::android { +class BufferQueueProducer; +} + +namespace Service::Nvnflinger { +class IHOSBinderDriver; +class SurfaceFlinger; +} // namespace Service::Nvnflinger + +namespace Service { +class Event; +} + +namespace Service::VI { + +class SharedBufferManager; + +class Container { +public: + explicit Container(Core::System& system); + ~Container(); + + void OnTerminate(); + + SharedBufferManager* GetSharedBufferManager(); + + Result GetBinderDriver(std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver); + Result GetLayerProducerHandle(std::shared_ptr<android::BufferQueueProducer>* out_producer, + u64 layer_id); + + Result OpenDisplay(u64* out_display_id, const DisplayName& display_name); + Result CloseDisplay(u64 display_id); + + // Managed layers are created by the interaction between am and ommdisp + // on behalf of an applet. Their lifetime ends with the lifetime of the + // applet's ISelfController. + Result CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid); + Result DestroyManagedLayer(u64 layer_id); + Result OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid); + Result CloseLayer(u64 layer_id); + + // Stray layers are created by non-applet sysmodules. Their lifetime ends + // with the lifetime of the IApplicationDisplayService which created them. + Result CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id); + Result DestroyStrayLayer(u64 layer_id); + + Result SetLayerVisibility(u64 layer_id, bool visible); + Result SetLayerBlending(u64 layer_id, bool enabled); + + void LinkVsyncEvent(u64 display_id, Event* event); + void UnlinkVsyncEvent(u64 display_id, Event* event); + +private: + Result CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid); + Result DestroyLayerLocked(u64 layer_id); + Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid); + Result CloseLayerLocked(u64 layer_id); + + void CreateBufferQueueLocked(Layer* layer); + void DestroyBufferQueueLocked(Layer* layer); + +public: + void ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); + +private: + std::mutex m_lock{}; + DisplayList m_displays{}; + LayerList m_layers{}; + std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_driver{}; + std::shared_ptr<Nvnflinger::SurfaceFlinger> m_surface_flinger{}; + std::optional<SharedBufferManager> m_shared_buffer_manager{}; + std::optional<Conductor> m_conductor{}; + bool m_is_shut_down{}; +}; + +} // namespace Service::VI 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 <algorithm> -#include <utility> - -#include <fmt/format.h> - -#include "common/assert.h" -#include "core/core.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/nvdrv/core/container.h" -#include "core/hle/service/nvnflinger/buffer_item_consumer.h" -#include "core/hle/service/nvnflinger/buffer_queue_consumer.h" -#include "core/hle/service/nvnflinger/buffer_queue_core.h" -#include "core/hle/service/nvnflinger/buffer_queue_producer.h" -#include "core/hle/service/nvnflinger/hardware_composer.h" -#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" -#include "core/hle/service/vi/display/vi_display.h" -#include "core/hle/service/vi/layer/vi_layer.h" -#include "core/hle/service/vi/vi_results.h" - -namespace Service::VI { - -struct BufferQueue { - std::shared_ptr<android::BufferQueueCore> core; - std::unique_ptr<android::BufferQueueProducer> producer; - std::unique_ptr<android::BufferQueueConsumer> consumer; -}; - -static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context, - Service::Nvidia::NvCore::NvMap& nvmap) { - auto buffer_queue_core = std::make_shared<android::BufferQueueCore>(); - return { - buffer_queue_core, - std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap), - std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)}; -} - -Display::Display(u64 id, std::string name_, - Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_, - KernelHelpers::ServiceContext& service_context_, Core::System& system_) - : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_}, - service_context{service_context_} { - hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>(); - vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id)); -} - -Display::~Display() { - service_context.CloseEvent(vsync_event); -} - -Layer& Display::GetLayer(std::size_t index) { - size_t i = 0; - for (auto& layer : layers) { - if (!layer->IsOpen() || !layer->IsVisible()) { - continue; - } - - if (i == index) { - return *layer; - } - - i++; - } - - UNREACHABLE(); -} - -size_t Display::GetNumLayers() const { - return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); }); -} - -Kernel::KReadableEvent* Display::GetVSyncEvent() { - return &vsync_event->GetReadableEvent(); -} - -void Display::SignalVSyncEvent() { - vsync_event->Signal(); -} - -void Display::CreateLayer(u64 layer_id, u32 binder_id, - Service::Nvidia::NvCore::Container& nv_core) { - auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile()); - - auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer)); - buffer_item_consumer->Connect(false); - - layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer, - std::move(buffer_item_consumer))); - - if (is_abandoned) { - this->FindLayer(layer_id)->GetConsumer().Abandon(); - } - - hos_binder_driver_server.RegisterProducer(std::move(producer)); -} - -void Display::DestroyLayer(u64 layer_id) { - if (auto* layer = this->FindLayer(layer_id); layer != nullptr) { - layer->GetConsumer().Abandon(); - } - - std::erase_if(layers, - [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; }); -} - -void Display::Abandon() { - for (auto& layer : layers) { - layer->GetConsumer().Abandon(); - } - is_abandoned = true; -} - -Layer* Display::FindLayer(u64 layer_id) { - const auto itr = - std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) { - return layer->GetLayerId() == layer_id; - }); - - if (itr == layers.end()) { - return nullptr; - } - - return itr->get(); -} - -const Layer* Display::FindLayer(u64 layer_id) const { - const auto itr = - std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) { - return layer->GetLayerId() == layer_id; - }); - - if (itr == layers.end()) { - return nullptr; - } - - return itr->get(); -} - -} // namespace Service::VI 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 <memory> -#include <string> -#include <vector> - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hle/result.h" - -namespace Core { -class System; -} - -namespace Kernel { -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service::android { -class BufferQueueProducer; -} - -namespace Service::KernelHelpers { -class ServiceContext; -} - -namespace Service::Nvnflinger { -class HardwareComposer; -class HosBinderDriverServer; -} // namespace Service::Nvnflinger - -namespace Service::Nvidia::NvCore { -class Container; -class NvMap; -} // namespace Service::Nvidia::NvCore - -namespace Service::VI { - -class Layer; - -/// Represents a single display type -class Display { -public: - YUZU_NON_COPYABLE(Display); - YUZU_NON_MOVEABLE(Display); - - /// Constructs a display with a given unique ID and name. - /// - /// @param id The unique ID for this display. - /// @param hos_binder_driver_server_ Nvnflinger HOSBinderDriver server instance. - /// @param service_context_ The ServiceContext for the owning service. - /// @param name_ The name for this display. - /// @param system_ The global system instance. - /// - Display(u64 id, std::string name_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_, - KernelHelpers::ServiceContext& service_context_, Core::System& system_); - ~Display(); - - /// Gets the unique ID assigned to this display. - u64 GetID() const { - return display_id; - } - - /// Gets the name of this display - const std::string& GetName() const { - return name; - } - - /// Whether or not this display has any layers added to it. - bool HasLayers() const { - return GetNumLayers() > 0; - } - - /// Gets a layer for this display based off an index. - Layer& GetLayer(std::size_t index); - - std::size_t GetNumLayers() const; - - /// Gets the internal vsync event. - Kernel::KReadableEvent* GetVSyncEvent(); - - /// Signals the internal vsync event. - void SignalVSyncEvent(); - - /// Creates and adds a layer to this display with the given ID. - /// - /// @param layer_id The ID to assign to the created layer. - /// @param binder_id The ID assigned to the buffer queue. - /// - void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core); - - /// Removes a layer from this display with the given ID. - /// - /// @param layer_id The ID assigned to the layer to destroy. - /// - void DestroyLayer(u64 layer_id); - - /// Resets the display for a new connection. - void Reset() { - layers.clear(); - } - - void Abandon(); - - /// Attempts to find a layer with the given ID. - /// - /// @param layer_id The layer ID. - /// - /// @returns If found, the Layer instance with the given ID. - /// If not found, then nullptr is returned. - /// - Layer* FindLayer(u64 layer_id); - - /// Attempts to find a layer with the given ID. - /// - /// @param layer_id The layer ID. - /// - /// @returns If found, the Layer instance with the given ID. - /// If not found, then nullptr is returned. - /// - const Layer* FindLayer(u64 layer_id) const; - - Nvnflinger::HardwareComposer& GetComposer() const { - return *hardware_composer; - } - -private: - u64 display_id; - std::string name; - Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; - KernelHelpers::ServiceContext& service_context; - - std::vector<std::unique_ptr<Layer>> layers; - std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer; - Kernel::KEvent* vsync_event{}; - bool is_abandoned{}; -}; - -} // namespace Service::VI 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 <cstring> + +#include "core/hle/service/vi/display.h" + +namespace Service::VI { + +class DisplayList { +public: + constexpr DisplayList() = default; + + bool CreateDisplay(const DisplayName& name) { + Display* const display = this->GetFreeDisplay(); + if (!display) { + return false; + } + + display->Initialize(m_next_id++, name); + return true; + } + + bool DestroyDisplay(u64 display_id) { + Display* display = this->GetDisplayById(display_id); + if (!display) { + return false; + } + + display->Finalize(); + return true; + } + + Display* GetDisplayByName(const DisplayName& name) { + for (auto& display : m_displays) { + if (display.IsInitialized() && + std::strncmp(name.data(), display.GetDisplayName().data(), sizeof(DisplayName)) == + 0) { + return &display; + } + } + + return nullptr; + } + + Display* GetDisplayById(u64 display_id) { + for (auto& display : m_displays) { + if (display.IsInitialized() && display.GetId() == display_id) { + return &display; + } + } + + return nullptr; + } + + template <typename F> + void ForEachDisplay(F&& cb) { + for (auto& display : m_displays) { + if (display.IsInitialized()) { + cb(display); + } + } + } + +private: + Display* GetFreeDisplay() { + for (auto& display : m_displays) { + if (!display.IsInitialized()) { + return &display; + } + } + + return nullptr; + } + +private: + std::array<Display, 8> m_displays{}; + u64 m_next_id{}; +}; + +} // namespace Service::VI 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<android::BufferItemConsumer>&& consumer_) - : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move( - consumer_)}, - blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {} - -Layer::~Layer() = default; - -} // namespace Service::VI 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 <memory> -#include <utility> - -#include "common/common_types.h" - -namespace Service::android { -class BufferItemConsumer; -class BufferQueueCore; -class BufferQueueProducer; -} // namespace Service::android - -namespace Service::Nvnflinger { -enum class LayerBlending : u32; -} - -namespace Service::VI { - -/// Represents a single display layer. -class Layer { -public: - /// Constructs a layer with a given ID and buffer queue. - /// - /// @param layer_id_ The ID to assign to this layer. - /// @param binder_id_ The binder ID to assign to this layer. - /// @param binder_ The buffer producer queue for this layer to use. - /// - Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, - android::BufferQueueProducer& binder_, - std::shared_ptr<android::BufferItemConsumer>&& consumer_); - ~Layer(); - - Layer(const Layer&) = delete; - Layer& operator=(const Layer&) = delete; - - Layer(Layer&&) = default; - Layer& operator=(Layer&&) = delete; - - /// Gets the ID for this layer. - u64 GetLayerId() const { - return layer_id; - } - - /// Gets the binder ID for this layer. - u32 GetBinderId() const { - return binder_id; - } - - /// Gets a reference to the buffer queue this layer is using. - android::BufferQueueProducer& GetBufferQueue() { - return binder; - } - - /// Gets a const reference to the buffer queue this layer is using. - const android::BufferQueueProducer& GetBufferQueue() const { - return binder; - } - - android::BufferItemConsumer& GetConsumer() { - return *consumer; - } - - const android::BufferItemConsumer& GetConsumer() const { - return *consumer; - } - - android::BufferQueueCore& Core() { - return core; - } - - const android::BufferQueueCore& Core() const { - return core; - } - - bool IsVisible() const { - return visible; - } - - void SetVisibility(bool v) { - visible = v; - } - - bool IsOpen() const { - return open; - } - - bool Close() { - return std::exchange(open, false); - } - - bool Open() { - return !std::exchange(open, true); - } - - Nvnflinger::LayerBlending GetBlending() { - return blending; - } - - void SetBlending(Nvnflinger::LayerBlending b) { - blending = b; - } - -private: - const u64 layer_id; - const u32 binder_id; - android::BufferQueueCore& core; - android::BufferQueueProducer& binder; - std::shared_ptr<android::BufferItemConsumer> consumer; - Service::Nvnflinger::LayerBlending blending; - bool open; - bool visible; -}; - -} // namespace Service::VI 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 <typename F> + void ForEachLayer(F&& cb) { + for (auto& layer : m_layers) { + if (layer.IsInitialized()) { + cb(layer); + } + } + } + +private: + Layer* GetFreeLayer() { + for (auto& layer : m_layers) { + if (!layer.IsInitialized()) { + return &layer; + } + } + + return nullptr; + } + +private: + std::array<Layer, 8> m_layers{}; + u64 m_next_id{}; +}; + +} // namespace Service::VI 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<Nvnflinger::Nvnflinger> surface_flinger) - : ServiceFramework{system_, "IManagerDisplayService"}, - m_surface_flinger{std::move(surface_flinger)} { +IManagerDisplayService::IManagerDisplayService(Core::System& system_, + std::shared_ptr<Container> container) + : ServiceFramework{system_, "IManagerDisplayService"}, m_container{std::move(container)} { // clang-format off 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<u64> out_layer_id, u32 unknown, - u64 display_id, AppletResourceUserId aruid) { - LOG_WARNING(Service_VI, "(STUBBED) called. unknown={}, display={}, aruid={}", unknown, - display_id, aruid.pid); +Result IManagerDisplayService::CreateSharedLayerSession(Kernel::KProcess* owner_process, + u64* out_buffer_id, u64* out_layer_handle, + u64 display_id, bool enable_blending) { + R_RETURN(m_container->GetSharedBufferManager()->CreateSession( + owner_process, out_buffer_id, out_layer_handle, display_id, enable_blending)); +} - const auto layer_id = m_surface_flinger->CreateLayer(display_id); - if (!layer_id) { - LOG_ERROR(Service_VI, "Layer not found! display={}", display_id); - R_THROW(VI::ResultNotFound); - } +void IManagerDisplayService::DestroySharedLayerSession(Kernel::KProcess* owner_process) { + m_container->GetSharedBufferManager()->DestroySession(owner_process); +} - *out_layer_id = *layer_id; - R_SUCCEED(); +Result IManagerDisplayService::SetLayerBlending(bool enabled, u64 layer_id) { + R_RETURN(m_container->SetLayerBlending(layer_id, enabled)); +} + +Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id, + AppletResourceUserId aruid) { + LOG_DEBUG(Service_VI, "called. flags={}, display={}, aruid={}", flags, display_id, aruid.pid); + R_RETURN(m_container->CreateManagedLayer(out_layer_id, display_id, aruid.pid)); +} + +Result IManagerDisplayService::DestroyManagedLayer(u64 layer_id) { + LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id); + R_RETURN(m_container->DestroyManagedLayer(layer_id)); } Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) { @@ -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<IManagerDisplayService> { public: - explicit IManagerDisplayService(Core::System& system_, - std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger); + explicit IManagerDisplayService(Core::System& system_, std::shared_ptr<Container> container); ~IManagerDisplayService() override; -private: - Result CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, u64 display_id, + Result CreateSharedLayerSession(Kernel::KProcess* owner_process, u64* out_buffer_id, + u64* out_layer_handle, u64 display_id, bool enable_blending); + void DestroySharedLayerSession(Kernel::KProcess* owner_process); + + Result SetLayerBlending(bool enabled, u64 layer_id); + +public: + Result CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id, AppletResourceUserId aruid); + 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<Nvnflinger::Nvnflinger> m_surface_flinger; + const std::shared_ptr<Container> 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<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager) - : ServiceFramework{system_, "vi:m"}, m_binder_service{std::move(binder_service)}, - m_shared_buffer_manager{std::move(shared_buffer_manager)} { +IManagerRootService::IManagerRootService(Core::System& system_, + std::shared_ptr<Container> container) + : ServiceFramework{system_, "vi:m"}, m_container{std::move(container)} { static const FunctionInfo functions[] = { {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -32,8 +31,8 @@ IManagerRootService::~IManagerRootService() = default; Result IManagerRootService::GetDisplayService( Out<SharedPointer<IApplicationDisplayService>> 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<IManagerRootService> { public: - explicit IManagerRootService(Core::System& system_, - std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager); + explicit IManagerRootService(Core::System& system_, std::shared_ptr<Container> container); ~IManagerRootService() override; Result GetDisplayService( @@ -32,8 +26,7 @@ public: Policy policy); private: - const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; - const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager; + const std::shared_ptr<Container> m_container; }; } // namespace Service::VI 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<IApplicationDisplayService>* out_application_display_service, - Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission, + Core::System& system, std::shared_ptr<Container> container, Permission permission, Policy policy) { if (!IsValidServiceAccess(permission, policy)) { @@ -32,7 +31,7 @@ Result GetApplicationDisplayService( } *out_application_display_service = - std::make_shared<IApplicationDisplayService>(system, binder_service, shared_buffer_manager); + std::make_shared<IApplicationDisplayService>(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<IApplicationDisplayService>* out_application_display_service, - Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission, + Core::System& system, std::shared_ptr<Container> container, Permission permission, Policy policy); } // namespace Service::VI diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp index e61c02e1c..869b18961 100644 --- a/src/core/hle/service/vi/fbshare_buffer_manager.cpp +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp @@ -11,8 +11,8 @@ #include "core/hle/service/nvnflinger/buffer_queue_producer.h" #include "core/hle/service/nvnflinger/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/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" @@ -203,16 +203,15 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han } // namespace -FbshareBufferManager::FbshareBufferManager(Core::System& system, - std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger, - std::shared_ptr<Nvidia::Module> nvdrv) - : m_system(system), m_surface_flinger(std::move(surface_flinger)), m_nvdrv(std::move(nvdrv)) {} +SharedBufferManager::SharedBufferManager(Core::System& system, Container& container, + std::shared_ptr<Nvidia::Module> nvdrv) + : m_system(system), m_container(container), m_nvdrv(std::move(nvdrv)) {} -FbshareBufferManager::~FbshareBufferManager() = default; +SharedBufferManager::~SharedBufferManager() = default; -Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, - u64* out_layer_handle, u64 display_id, - Nvnflinger::LayerBlending blending) { +Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, + u64* out_layer_handle, u64 display_id, + bool enable_blending) { std::scoped_lock lk{m_guard}; // Ensure we haven't already created. @@ -237,7 +236,7 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou owner_process, m_system)); // Create new session. - auto [it, was_emplaced] = m_sessions.emplace(aruid, FbshareSession{}); + auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{}); auto& session = it->second; auto& container = m_nvdrv->GetContainer(); @@ -249,17 +248,18 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou 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); + s32 producer_binder_id; + R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id), + std::addressof(session.layer_id), display_id)); - // Get the layer. - VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, session.layer_id); - ASSERT(layer != nullptr); + // Configure blending. + R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending)); // Get the producer and set preallocated buffers. - auto& producer = layer->GetBufferQueue(); - MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle); - MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id)); + MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle); + MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle); // Assign outputs. *out_buffer_id = m_buffer_id; @@ -269,7 +269,7 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou R_SUCCEED(); } -void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) { +void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) { std::scoped_lock lk{m_guard}; if (m_buffer_id == 0) { @@ -285,7 +285,7 @@ void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) { auto& session = it->second; // Destroy the layer. - m_surface_flinger->DestroyLayer(session.layer_id); + R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); // Close nvmap handle. FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); @@ -301,11 +301,11 @@ void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) { m_sessions.erase(it); } -Result FbshareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, - s32* out_nvmap_handle, - SharedMemoryPoolLayout* out_pool_layout, - u64 buffer_id, - u64 applet_resource_user_id) { +Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, + s32* out_nvmap_handle, + SharedMemoryPoolLayout* out_pool_layout, + u64 buffer_id, + u64 applet_resource_user_id) { std::scoped_lock lk{m_guard}; R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); @@ -319,36 +319,20 @@ Result FbshareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, R_SUCCEED(); } -Result FbshareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) { - // Ensure the layer id is valid. - R_UNLESS(layer_id > 0, VI::ResultNotFound); - - // Get the layer. - VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, layer_id); - R_UNLESS(layer != nullptr, VI::ResultNotFound); - - // We succeeded. - *out_layer = layer; - R_SUCCEED(); -} - -Result FbshareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, - std::array<s32, 4>& out_slot_indexes, - s64* out_target_slot, u64 layer_id) { +Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, + std::array<s32, 4>& out_slot_indexes, + s64* out_target_slot, u64 layer_id) { std::scoped_lock lk{m_guard}; - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); - // Get the producer. - auto& producer = layer->GetBufferQueue(); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); // Get the next buffer from the producer. s32 slot; - R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, - SharedBufferWidth, SharedBufferHeight, - SharedBufferBlockLinearFormat, 0) == android::Status::NoError, + R_UNLESS(producer->DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, + SharedBufferWidth, SharedBufferHeight, + SharedBufferBlockLinearFormat, 0) == android::Status::NoError, VI::ResultOperationFailed); // Assign remaining outputs. @@ -359,27 +343,24 @@ Result FbshareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, R_SUCCEED(); } -Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence, - Common::Rectangle<s32> crop_region, - u32 transform, s32 swap_interval, - u64 layer_id, s64 slot) { +Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, + Common::Rectangle<s32> crop_region, + u32 transform, s32 swap_interval, u64 layer_id, + s64 slot) { std::scoped_lock lk{m_guard}; - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); - // Get the producer. - auto& producer = layer->GetBufferQueue(); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); // Request to queue the buffer. std::shared_ptr<android::GraphicBuffer> buffer; - R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == + R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == android::Status::NoError, VI::ResultOperationFailed); ON_RESULT_FAILURE { - producer.CancelBuffer(static_cast<s32>(slot), fence); + producer->CancelBuffer(static_cast<s32>(slot), fence); }; // Queue the buffer to the producer. @@ -389,7 +370,7 @@ Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence, input.fence = fence; input.transform = static_cast<android::NativeWindowTransform>(transform); input.swap_interval = swap_interval; - R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == + R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == android::Status::NoError, VI::ResultOperationFailed); @@ -397,25 +378,36 @@ Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence, R_SUCCEED(); } -Result FbshareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, - u64 layer_id) { +Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { std::scoped_lock lk{m_guard}; - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); + // Get the producer. + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); + + // Cancel. + producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence()); + + // We succeeded. + R_SUCCEED(); +} + +Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, + u64 layer_id) { + std::scoped_lock lk{m_guard}; // Get the producer. - auto& producer = layer->GetBufferQueue(); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); // Set the event. - *out_event = std::addressof(producer.GetNativeHandle()); + *out_event = producer->GetNativeHandle({}); // We succeeded. R_SUCCEED(); } -Result FbshareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { +Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); Common::ScratchBuffer<u32> scratch; diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.h b/src/core/hle/service/vi/shared_buffer_manager.h index b9e99e61f..7c9bb7199 100644 --- a/src/core/hle/service/vi/fbshare_buffer_manager.h +++ b/src/core/hle/service/vi/shared_buffer_manager.h @@ -8,16 +8,28 @@ #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; +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; @@ -32,18 +44,17 @@ struct SharedMemoryPoolLayout { }; static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); -struct FbshareSession; +struct SharedBufferSession; -class FbshareBufferManager final { +class SharedBufferManager final { public: - explicit FbshareBufferManager(Core::System& system, - std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger, - std::shared_ptr<Nvidia::Module> nvdrv); - ~FbshareBufferManager(); + explicit SharedBufferManager(Core::System& system, Container& container, + std::shared_ptr<Nvidia::Module> nvdrv); + ~SharedBufferManager(); - Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, - u64 display_id, Nvnflinger::LayerBlending blending); - void Finalize(Kernel::KProcess* owner_process); + Result CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, + u64 display_id, bool enable_blending); + void DestroySession(Kernel::KProcess* owner_process); Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, @@ -52,28 +63,26 @@ public: s64* out_target_slot, u64 layer_id); Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> 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: - 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<u64, FbshareSession> m_sessions; + std::map<u64, SharedBufferSession> m_sessions; std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; std::mutex m_guard; Core::System& m_system; - const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger; + Container& m_container; const std::shared_ptr<Nvidia::Module> m_nvdrv; }; -struct FbshareSession { +struct SharedBufferSession { Nvidia::DeviceFD nvmap_fd = {}; Nvidia::NvCore::SessionId session_id = {}; u64 layer_id = {}; 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<Nvnflinger::Nvnflinger> surface_flinger, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager) - : ServiceFramework{system_, "ISystemDisplayService"}, - m_surface_flinger{std::move(surface_flinger)}, - m_shared_buffer_manager{std::move(shared_buffer_manager)} { +ISystemDisplayService::ISystemDisplayService(Core::System& system_, + std::shared_ptr<Container> container) + : ServiceFramework{system_, "ISystemDisplayService"}, m_container{std::move(container)} { // clang-format off 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<android::Fence> out_f Out<std::array<s32, 4>> out_slots, Out<s64> 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<Kernel::KReadableEvent> 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<ISystemDisplayService> { public: - explicit ISystemDisplayService(Core::System& system_, - std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager); + explicit ISystemDisplayService(Core::System& system_, std::shared_ptr<Container> container); ~ISystemDisplayService() override; private: @@ -42,10 +36,10 @@ private: Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> 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<Nvnflinger::Nvnflinger> m_surface_flinger; - const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager; + const std::shared_ptr<Container> 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<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager) - : ServiceFramework{system_, "vi:s"}, m_binder_service{std::move(binder_service)}, - m_shared_buffer_manager{std::move(shared_buffer_manager)} { +ISystemRootService::ISystemRootService(Core::System& system_, std::shared_ptr<Container> container) + : ServiceFramework{system_, "vi:s"}, m_container{std::move(container)} { static const FunctionInfo functions[] = { {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -27,8 +25,8 @@ ISystemRootService::~ISystemRootService() = default; Result ISystemRootService::GetDisplayService( Out<SharedPointer<IApplicationDisplayService>> 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<ISystemRootService> { public: - explicit ISystemRootService(Core::System& system_, - std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, - std::shared_ptr<FbshareBufferManager> shared_buffer_manager); + explicit ISystemRootService(Core::System& system_, std::shared_ptr<Container> container); ~ISystemRootService() override; private: @@ -32,8 +26,7 @@ private: Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy); - const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; - const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager; + const std::shared_ptr<Container> m_container; }; } // namespace Service::VI 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<Nvnflinger::IHOSBinderDriver>("dispdrv", true); - const auto nvdrv = - system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule(); - const auto shared_buffer_manager = - std::make_shared<FbshareBufferManager>(system, binder_service->GetSurfaceFlinger(), nvdrv); +void LoopProcess(Core::System& system, std::stop_token token) { + const auto container = std::make_shared<Container>(system); auto server_manager = std::make_unique<ServerManager>(system); + server_manager->RegisterNamedService("vi:m", + std::make_shared<IManagerRootService>(system, container)); + server_manager->RegisterNamedService("vi:s", + std::make_shared<ISystemRootService>(system, container)); server_manager->RegisterNamedService( - "vi:m", - std::make_shared<IManagerRootService>(system, binder_service, shared_buffer_manager)); - server_manager->RegisterNamedService( - "vi:s", - std::make_shared<ISystemRootService>(system, binder_service, shared_buffer_manager)); - server_manager->RegisterNamedService( - "vi:u", - std::make_shared<IApplicationRootService>(system, binder_service, shared_buffer_manager)); + "vi:u", std::make_shared<IApplicationRootService>(system, container)); + + std::stop_callback cb(token, [=] { container->OnTerminate(); }); + ServerManager::RunServer(std::move(server_manager)); } 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<u64>(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 <set> + +namespace Service { +class Event; +} + +namespace Service::VI { + +class DisplayList; + +class VsyncManager { +public: + explicit VsyncManager(); + ~VsyncManager(); + + void SignalVsync(); + void LinkVsyncEvent(Event* event); + void UnlinkVsyncEvent(Event* event); + +private: + std::set<Event*> m_vsync_events; +}; + +} // namespace Service::VI |