vi: manage resources independently of nvnflinger and refactor

This commit is contained in:
Liam 2024-02-14 23:44:05 -05:00
parent e34074861c
commit f5d736af4b
62 changed files with 1758 additions and 1492 deletions

View file

@ -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();
}

View file

@ -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};
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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.
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());
// Cancel.
producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence());
// We succeeded.
R_SUCCEED();
}
Result FbshareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
u64 layer_id) {
std::scoped_lock lk{m_guard};
// Get the producer.
std::shared_ptr<android::BufferQueueProducer> 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<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
Common::ScratchBuffer<u32> scratch;

View file

@ -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 = {};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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));
}

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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