Files
eden/src/core/hle/service/vi/container.cpp
T
Maufeat 1eed7efd09 [core, display, overlay] Add LayerIsOverlay to separate overlay on composer, stub RequestListSummaryOverlayNotification, sync emu settings when setting language (#3123)
This should fix the issue with, for example, ToTK running at 60 FPS when overlay applet is running.
This also should always run the overlay as actual overlay and not in the back.
Stubs RequestListSummaryOverlayNotifications in friends
Syncs Language of the Emulator, when setting language, this is used in Starter Applet

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3123
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
2025-12-17 06:26:02 +01:00

272 lines
9.1 KiB
C++

// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// 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) { this->DestroyLayerLocked(layer.GetId()); });
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();
}
Result Container::SetLayerZIndex(u64 layer_id, s32 z_index) {
std::scoped_lock lk{m_lock};
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
if (auto layer_ref = m_surface_flinger->FindLayer(layer->GetConsumerBinderId())) {
LOG_DEBUG(Service_VI, "called, SetLayerZIndex layer_id={} z={} (cid={})", layer_id,
z_index, layer->GetConsumerBinderId());
layer_ref->z_index = z_index;
} else {
LOG_DEBUG(Service_VI, "called, SetLayerZIndex failed to find layer for layer_id={} (cid={})",
layer_id, layer->GetConsumerBinderId());
}
R_SUCCEED();
}
Result Container::GetLayerZIndex(u64 layer_id, s32* out_z_index) {
std::scoped_lock lk{m_lock};
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
if (auto layer_ref = m_surface_flinger->FindLayer(layer->GetConsumerBinderId())) {
*out_z_index = layer_ref->z_index;
R_SUCCEED();
}
R_RETURN(VI::ResultNotFound);
}
Result Container::SetLayerIsOverlay(u64 layer_id, bool is_overlay) {
std::scoped_lock lk{m_lock};
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
m_surface_flinger->SetLayerIsOverlay(layer->GetConsumerBinderId(), is_overlay);
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);
s32 consumer_binder_id, producer_binder_id;
m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
auto* const layer =
m_layers.CreateLayer(owner_aruid, display, consumer_binder_id, producer_binder_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
m_surface_flinger->CreateLayer(consumer_binder_id);
*out_layer_id = layer->GetId();
R_SUCCEED();
}
Result Container::DestroyLayerLocked(u64 layer_id) {
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
m_surface_flinger->DestroyLayer(layer->GetConsumerBinderId());
m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
layer->GetProducerBinderId());
m_layers.DestroyLayer(layer_id);
R_SUCCEED();
}
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);
layer->Open();
if (auto* display = layer->GetDisplay(); display != nullptr) {
m_surface_flinger->AddLayerToDisplayStack(display->GetId(), layer->GetConsumerBinderId());
}
*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);
if (auto* display = layer->GetDisplay(); display != nullptr) {
m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
layer->GetConsumerBinderId());
}
layer->Close();
R_SUCCEED();
}
bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
u64 display_id) {
std::scoped_lock lk{m_lock};
return m_surface_flinger->ComposeDisplay(out_swap_interval, out_compose_speed_scale,
display_id);
}
} // namespace Service::VI