mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	Merge pull request #13035 from liamwhite/vi2
vi: manage resources independently of nvnflinger and refactor
This commit is contained in:
		@@ -423,12 +423,12 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/am/applet_manager.h
 | 
			
		||||
    hle/service/am/applet_message_queue.cpp
 | 
			
		||||
    hle/service/am/applet_message_queue.h
 | 
			
		||||
    hle/service/am/display_layer_manager.cpp
 | 
			
		||||
    hle/service/am/display_layer_manager.h
 | 
			
		||||
    hle/service/am/hid_registration.cpp
 | 
			
		||||
    hle/service/am/hid_registration.h
 | 
			
		||||
    hle/service/am/library_applet_storage.cpp
 | 
			
		||||
    hle/service/am/library_applet_storage.h
 | 
			
		||||
    hle/service/am/managed_layer_holder.cpp
 | 
			
		||||
    hle/service/am/managed_layer_holder.h
 | 
			
		||||
    hle/service/am/process.cpp
 | 
			
		||||
    hle/service/am/process.h
 | 
			
		||||
    hle/service/am/service/all_system_applet_proxies_service.cpp
 | 
			
		||||
@@ -481,8 +481,6 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/am/service/system_applet_proxy.h
 | 
			
		||||
    hle/service/am/service/window_controller.cpp
 | 
			
		||||
    hle/service/am/service/window_controller.h
 | 
			
		||||
    hle/service/am/system_buffer_manager.cpp
 | 
			
		||||
    hle/service/am/system_buffer_manager.h
 | 
			
		||||
    hle/service/aoc/aoc_u.cpp
 | 
			
		||||
    hle/service/aoc/aoc_u.h
 | 
			
		||||
    hle/service/apm/apm.cpp
 | 
			
		||||
@@ -833,12 +831,12 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/nvnflinger/consumer_base.cpp
 | 
			
		||||
    hle/service/nvnflinger/consumer_base.h
 | 
			
		||||
    hle/service/nvnflinger/consumer_listener.h
 | 
			
		||||
    hle/service/nvnflinger/fb_share_buffer_manager.cpp
 | 
			
		||||
    hle/service/nvnflinger/fb_share_buffer_manager.h
 | 
			
		||||
    hle/service/nvnflinger/graphic_buffer_producer.cpp
 | 
			
		||||
    hle/service/nvnflinger/graphic_buffer_producer.h
 | 
			
		||||
    hle/service/nvnflinger/hos_binder_driver_server.cpp
 | 
			
		||||
    hle/service/nvnflinger/hos_binder_driver_server.h
 | 
			
		||||
    hle/service/nvnflinger/hos_binder_driver.cpp
 | 
			
		||||
    hle/service/nvnflinger/hos_binder_driver.h
 | 
			
		||||
    hle/service/nvnflinger/hardware_composer.cpp
 | 
			
		||||
    hle/service/nvnflinger/hardware_composer.h
 | 
			
		||||
    hle/service/nvnflinger/hwc_layer.h
 | 
			
		||||
@@ -848,6 +846,8 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/nvnflinger/pixel_format.h
 | 
			
		||||
    hle/service/nvnflinger/producer_listener.h
 | 
			
		||||
    hle/service/nvnflinger/status.h
 | 
			
		||||
    hle/service/nvnflinger/surface_flinger.cpp
 | 
			
		||||
    hle/service/nvnflinger/surface_flinger.h
 | 
			
		||||
    hle/service/nvnflinger/ui/fence.h
 | 
			
		||||
    hle/service/nvnflinger/ui/graphic_buffer.cpp
 | 
			
		||||
    hle/service/nvnflinger/ui/graphic_buffer.h
 | 
			
		||||
@@ -941,6 +941,8 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/server_manager.h
 | 
			
		||||
    hle/service/service.cpp
 | 
			
		||||
    hle/service/service.h
 | 
			
		||||
    hle/service/services.cpp
 | 
			
		||||
    hle/service/services.h
 | 
			
		||||
    hle/service/set/setting_formats/appln_settings.cpp
 | 
			
		||||
    hle/service/set/setting_formats/appln_settings.h
 | 
			
		||||
    hle/service/set/setting_formats/device_settings.cpp
 | 
			
		||||
@@ -988,22 +990,26 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/ssl/ssl_backend.h
 | 
			
		||||
    hle/service/usb/usb.cpp
 | 
			
		||||
    hle/service/usb/usb.h
 | 
			
		||||
    hle/service/vi/display/vi_display.cpp
 | 
			
		||||
    hle/service/vi/display/vi_display.h
 | 
			
		||||
    hle/service/vi/layer/vi_layer.cpp
 | 
			
		||||
    hle/service/vi/layer/vi_layer.h
 | 
			
		||||
    hle/service/vi/application_display_service.cpp
 | 
			
		||||
    hle/service/vi/application_display_service.h
 | 
			
		||||
    hle/service/vi/application_root_service.cpp
 | 
			
		||||
    hle/service/vi/application_root_service.h
 | 
			
		||||
    hle/service/vi/hos_binder_driver.cpp
 | 
			
		||||
    hle/service/vi/hos_binder_driver.h
 | 
			
		||||
    hle/service/vi/conductor.cpp
 | 
			
		||||
    hle/service/vi/conductor.h
 | 
			
		||||
    hle/service/vi/container.cpp
 | 
			
		||||
    hle/service/vi/container.h
 | 
			
		||||
    hle/service/vi/display_list.h
 | 
			
		||||
    hle/service/vi/display.h
 | 
			
		||||
    hle/service/vi/layer_list.h
 | 
			
		||||
    hle/service/vi/layer.h
 | 
			
		||||
    hle/service/vi/manager_display_service.cpp
 | 
			
		||||
    hle/service/vi/manager_display_service.h
 | 
			
		||||
    hle/service/vi/manager_root_service.cpp
 | 
			
		||||
    hle/service/vi/manager_root_service.h
 | 
			
		||||
    hle/service/vi/service_creator.cpp
 | 
			
		||||
    hle/service/vi/service_creator.h
 | 
			
		||||
    hle/service/vi/shared_buffer_manager.cpp
 | 
			
		||||
    hle/service/vi/shared_buffer_manager.h
 | 
			
		||||
    hle/service/vi/system_display_service.cpp
 | 
			
		||||
    hle/service/vi/system_display_service.h
 | 
			
		||||
    hle/service/vi/system_root_service.cpp
 | 
			
		||||
@@ -1012,6 +1018,8 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/vi/vi_types.h
 | 
			
		||||
    hle/service/vi/vi.cpp
 | 
			
		||||
    hle/service/vi/vi.h
 | 
			
		||||
    hle/service/vi/vsync_manager.cpp
 | 
			
		||||
    hle/service/vi/vsync_manager.h
 | 
			
		||||
    internal_network/network.cpp
 | 
			
		||||
    internal_network/network.h
 | 
			
		||||
    internal_network/network_interface.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@
 | 
			
		||||
#include "core/hle/service/psc/time/system_clock.h"
 | 
			
		||||
#include "core/hle/service/psc/time/time_zone_service.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
#include "core/hle/service/services.h"
 | 
			
		||||
#include "core/hle/service/set/system_settings_server.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "core/internal_network/network.h"
 | 
			
		||||
@@ -310,7 +311,8 @@ struct System::Impl {
 | 
			
		||||
        audio_core = std::make_unique<AudioCore::AudioCore>(system);
 | 
			
		||||
 | 
			
		||||
        service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
 | 
			
		||||
        services = std::make_unique<Service::Services>(service_manager, system);
 | 
			
		||||
        services =
 | 
			
		||||
            std::make_unique<Service::Services>(service_manager, system, stop_event.get_token());
 | 
			
		||||
 | 
			
		||||
        is_powered_on = true;
 | 
			
		||||
        exit_locked = false;
 | 
			
		||||
@@ -458,11 +460,10 @@ struct System::Impl {
 | 
			
		||||
            gpu_core->NotifyShutdown();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        stop_event.request_stop();
 | 
			
		||||
        core_timing.SyncPause(false);
 | 
			
		||||
        Network::CancelPendingSocketOperations();
 | 
			
		||||
        kernel.SuspendEmulation(true);
 | 
			
		||||
        if (services) {
 | 
			
		||||
            services->KillNVNFlinger();
 | 
			
		||||
        }
 | 
			
		||||
        kernel.CloseServices();
 | 
			
		||||
        kernel.ShutdownCores();
 | 
			
		||||
        applet_manager.Reset();
 | 
			
		||||
@@ -480,6 +481,7 @@ struct System::Impl {
 | 
			
		||||
        cpu_manager.Shutdown();
 | 
			
		||||
        debugger.reset();
 | 
			
		||||
        kernel.Shutdown();
 | 
			
		||||
        stop_event = {};
 | 
			
		||||
        Network::RestartSocketOperations();
 | 
			
		||||
 | 
			
		||||
        if (auto room_member = room_network.GetRoomMember().lock()) {
 | 
			
		||||
@@ -615,6 +617,7 @@ struct System::Impl {
 | 
			
		||||
 | 
			
		||||
    ExecuteProgramCallback execute_program_callback;
 | 
			
		||||
    ExitCallback exit_callback;
 | 
			
		||||
    std::stop_source stop_event;
 | 
			
		||||
 | 
			
		||||
    std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
 | 
			
		||||
    std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
 | 
			
		||||
 
 | 
			
		||||
@@ -8,13 +8,13 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
 | 
			
		||||
void LoopProcess(Core::System& system) {
 | 
			
		||||
    auto server_manager = std::make_unique<ServerManager>(system);
 | 
			
		||||
 | 
			
		||||
    server_manager->RegisterNamedService(
 | 
			
		||||
        "appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, nvnflinger));
 | 
			
		||||
    server_manager->RegisterNamedService(
 | 
			
		||||
        "appletOE", std::make_shared<IApplicationProxyService>(system, nvnflinger));
 | 
			
		||||
    server_manager->RegisterNamedService("appletAE",
 | 
			
		||||
                                         std::make_shared<IAllSystemAppletProxiesService>(system));
 | 
			
		||||
    server_manager->RegisterNamedService("appletOE",
 | 
			
		||||
                                         std::make_shared<IApplicationProxyService>(system));
 | 
			
		||||
    ServerManager::RunServer(std::move(server_manager));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,8 @@ namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
 | 
			
		||||
void LoopProcess(Core::System& system);
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,9 @@
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/am/am_types.h"
 | 
			
		||||
#include "core/hle/service/am/applet_message_queue.h"
 | 
			
		||||
#include "core/hle/service/am/display_layer_manager.h"
 | 
			
		||||
#include "core/hle/service/am/hid_registration.h"
 | 
			
		||||
#include "core/hle/service/am/managed_layer_holder.h"
 | 
			
		||||
#include "core/hle/service/am/process.h"
 | 
			
		||||
#include "core/hle/service/am/system_buffer_manager.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
@@ -54,8 +53,7 @@ struct Applet {
 | 
			
		||||
    HidRegistration hid_registration;
 | 
			
		||||
 | 
			
		||||
    // vi state
 | 
			
		||||
    SystemBufferManager system_buffer_manager{};
 | 
			
		||||
    ManagedLayerHolder managed_layer_holder{};
 | 
			
		||||
    DisplayLayerManager display_layer_manager{};
 | 
			
		||||
 | 
			
		||||
    // Applet common functions
 | 
			
		||||
    Result terminate_result{};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										151
									
								
								src/core/hle/service/am/display_layer_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/core/hle/service/am/display_layer_manager.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/service/am/display_layer_manager.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "core/hle/service/vi/application_display_service.h"
 | 
			
		||||
#include "core/hle/service/vi/container.h"
 | 
			
		||||
#include "core/hle/service/vi/manager_display_service.h"
 | 
			
		||||
#include "core/hle/service/vi/manager_root_service.h"
 | 
			
		||||
#include "core/hle/service/vi/shared_buffer_manager.h"
 | 
			
		||||
#include "core/hle/service/vi/vi_results.h"
 | 
			
		||||
#include "core/hle/service/vi/vi_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
DisplayLayerManager::DisplayLayerManager() = default;
 | 
			
		||||
DisplayLayerManager::~DisplayLayerManager() {
 | 
			
		||||
    this->Finalize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process,
 | 
			
		||||
                                     AppletId applet_id, LibraryAppletMode mode) {
 | 
			
		||||
    R_ASSERT(system.ServiceManager()
 | 
			
		||||
                 .GetService<VI::IManagerRootService>("vi:m", true)
 | 
			
		||||
                 ->GetDisplayService(&m_display_service, VI::Policy::Compositor));
 | 
			
		||||
    R_ASSERT(m_display_service->GetManagerDisplayService(&m_manager_display_service));
 | 
			
		||||
 | 
			
		||||
    m_process = process;
 | 
			
		||||
    m_system_shared_buffer_id = 0;
 | 
			
		||||
    m_system_shared_layer_id = 0;
 | 
			
		||||
    m_applet_id = applet_id;
 | 
			
		||||
    m_buffer_sharing_enabled = false;
 | 
			
		||||
    m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
 | 
			
		||||
                         mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DisplayLayerManager::Finalize() {
 | 
			
		||||
    if (!m_manager_display_service) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clean up managed layers.
 | 
			
		||||
    for (const auto& layer : m_managed_display_layers) {
 | 
			
		||||
        m_manager_display_service->DestroyManagedLayer(layer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (const auto& layer : m_managed_display_recording_layers) {
 | 
			
		||||
        m_manager_display_service->DestroyManagedLayer(layer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clean up shared layers.
 | 
			
		||||
    if (m_buffer_sharing_enabled) {
 | 
			
		||||
        m_manager_display_service->DestroySharedLayerSession(m_process);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_manager_display_service = nullptr;
 | 
			
		||||
    m_display_service = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
 | 
			
		||||
    R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
 | 
			
		||||
 | 
			
		||||
    // TODO(Subv): Find out how AM determines the display to use, for now just
 | 
			
		||||
    // create the layer in the Default display.
 | 
			
		||||
    u64 display_id;
 | 
			
		||||
    R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
 | 
			
		||||
    R_TRY(m_manager_display_service->CreateManagedLayer(
 | 
			
		||||
        out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
 | 
			
		||||
 | 
			
		||||
    m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
 | 
			
		||||
    m_managed_display_layers.emplace(*out_layer_id);
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer_id,
 | 
			
		||||
                                                               u64* out_recording_layer_id) {
 | 
			
		||||
    R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
 | 
			
		||||
 | 
			
		||||
    // TODO(Subv): Find out how AM determines the display to use, for now just
 | 
			
		||||
    // create the layer in the Default display.
 | 
			
		||||
    // This calls nn::vi::CreateRecordingLayer() which creates another layer.
 | 
			
		||||
    // Currently we do not support more than 1 layer per display, output 1 layer id for now.
 | 
			
		||||
    // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
 | 
			
		||||
    // side effects.
 | 
			
		||||
    *out_recording_layer_id = 0;
 | 
			
		||||
    R_RETURN(this->CreateManagedDisplayLayer(out_layer_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
 | 
			
		||||
    // Succeed if already enabled.
 | 
			
		||||
    R_SUCCEED_IF(m_buffer_sharing_enabled);
 | 
			
		||||
 | 
			
		||||
    // Ensure we can access shared layers.
 | 
			
		||||
    R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
 | 
			
		||||
    R_UNLESS(m_applet_id != AppletId::Application, VI::ResultPermissionDenied);
 | 
			
		||||
 | 
			
		||||
    // Create the shared layer.
 | 
			
		||||
    u64 display_id;
 | 
			
		||||
    R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
 | 
			
		||||
    R_TRY(m_manager_display_service->CreateSharedLayerSession(m_process, &m_system_shared_buffer_id,
 | 
			
		||||
                                                              &m_system_shared_layer_id, display_id,
 | 
			
		||||
                                                              m_blending_enabled));
 | 
			
		||||
 | 
			
		||||
    // We succeeded, so set up remaining state.
 | 
			
		||||
    m_buffer_sharing_enabled = true;
 | 
			
		||||
    m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
 | 
			
		||||
                                                       u64* out_system_shared_layer_id) {
 | 
			
		||||
    R_TRY(this->IsSystemBufferSharingEnabled());
 | 
			
		||||
 | 
			
		||||
    *out_system_shared_buffer_id = m_system_shared_buffer_id;
 | 
			
		||||
    *out_system_shared_layer_id = m_system_shared_layer_id;
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DisplayLayerManager::SetWindowVisibility(bool visible) {
 | 
			
		||||
    if (m_visible == visible) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_visible = visible;
 | 
			
		||||
 | 
			
		||||
    if (m_manager_display_service) {
 | 
			
		||||
        if (m_system_shared_layer_id) {
 | 
			
		||||
            m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (const auto layer_id : m_managed_display_layers) {
 | 
			
		||||
            m_manager_display_service->SetLayerVisibility(m_visible, layer_id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DisplayLayerManager::GetWindowVisibility() const {
 | 
			
		||||
    return m_visible;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
 | 
			
		||||
                                                     s32* out_fbshare_layer_index) {
 | 
			
		||||
    R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
 | 
			
		||||
    R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
 | 
			
		||||
        out_was_written, out_fbshare_layer_index));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM
 | 
			
		||||
							
								
								
									
										62
									
								
								src/core/hle/service/am/display_layer_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/core/hle/service/am/display_layer_manager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <set>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
#include "core/hle/service/am/am_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
class KProcess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
class IApplicationDisplayService;
 | 
			
		||||
class IManagerDisplayService;
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
class DisplayLayerManager {
 | 
			
		||||
public:
 | 
			
		||||
    explicit DisplayLayerManager();
 | 
			
		||||
    ~DisplayLayerManager();
 | 
			
		||||
 | 
			
		||||
    void Initialize(Core::System& system, Kernel::KProcess* process, AppletId applet_id,
 | 
			
		||||
                    LibraryAppletMode mode);
 | 
			
		||||
    void Finalize();
 | 
			
		||||
 | 
			
		||||
    Result CreateManagedDisplayLayer(u64* out_layer_id);
 | 
			
		||||
    Result CreateManagedDisplaySeparableLayer(u64* out_layer_id, u64* out_recording_layer_id);
 | 
			
		||||
 | 
			
		||||
    Result IsSystemBufferSharingEnabled();
 | 
			
		||||
    Result GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
 | 
			
		||||
                                      u64* out_system_shared_layer_id);
 | 
			
		||||
 | 
			
		||||
    void SetWindowVisibility(bool visible);
 | 
			
		||||
    bool GetWindowVisibility() const;
 | 
			
		||||
 | 
			
		||||
    Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Kernel::KProcess* m_process{};
 | 
			
		||||
    std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
 | 
			
		||||
    std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
 | 
			
		||||
    std::set<u64> m_managed_display_layers{};
 | 
			
		||||
    std::set<u64> m_managed_display_recording_layers{};
 | 
			
		||||
    u64 m_system_shared_buffer_id{};
 | 
			
		||||
    u64 m_system_shared_layer_id{};
 | 
			
		||||
    AppletId m_applet_id{};
 | 
			
		||||
    bool m_buffer_sharing_enabled{};
 | 
			
		||||
    bool m_blending_enabled{};
 | 
			
		||||
    bool m_visible{true};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM
 | 
			
		||||
@@ -1,59 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/am/managed_layer_holder.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
ManagedLayerHolder::ManagedLayerHolder() = default;
 | 
			
		||||
ManagedLayerHolder::~ManagedLayerHolder() {
 | 
			
		||||
    if (!m_nvnflinger) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (const auto& layer : m_managed_display_layers) {
 | 
			
		||||
        m_nvnflinger->DestroyLayer(layer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (const auto& layer : m_managed_display_recording_layers) {
 | 
			
		||||
        m_nvnflinger->DestroyLayer(layer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_nvnflinger = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
 | 
			
		||||
    m_nvnflinger = nvnflinger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
 | 
			
		||||
    // TODO(Subv): Find out how AM determines the display to use, for now just
 | 
			
		||||
    // create the layer in the Default display.
 | 
			
		||||
    const auto display_id = m_nvnflinger->OpenDisplay("Default");
 | 
			
		||||
    const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
 | 
			
		||||
 | 
			
		||||
    m_managed_display_layers.emplace(*layer_id);
 | 
			
		||||
 | 
			
		||||
    *out_layer = *layer_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
 | 
			
		||||
                                                            u64* out_recording_layer) {
 | 
			
		||||
    // TODO(Subv): Find out how AM determines the display to use, for now just
 | 
			
		||||
    // create the layer in the Default display.
 | 
			
		||||
    // This calls nn::vi::CreateRecordingLayer() which creates another layer.
 | 
			
		||||
    // Currently we do not support more than 1 layer per display, output 1 layer id for now.
 | 
			
		||||
    // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
 | 
			
		||||
    // side effects.
 | 
			
		||||
    // TODO: Support multiple layers
 | 
			
		||||
    const auto display_id = m_nvnflinger->OpenDisplay("Default");
 | 
			
		||||
    const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
 | 
			
		||||
 | 
			
		||||
    m_managed_display_layers.emplace(*layer_id);
 | 
			
		||||
 | 
			
		||||
    *out_layer = *layer_id;
 | 
			
		||||
    *out_recording_layer = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <set>
 | 
			
		||||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
class ManagedLayerHolder {
 | 
			
		||||
public:
 | 
			
		||||
    ManagedLayerHolder();
 | 
			
		||||
    ~ManagedLayerHolder();
 | 
			
		||||
 | 
			
		||||
    void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
 | 
			
		||||
    void CreateManagedDisplayLayer(u64* out_layer);
 | 
			
		||||
    void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Nvnflinger::Nvnflinger* m_nvnflinger{};
 | 
			
		||||
    std::set<u64> m_managed_display_layers{};
 | 
			
		||||
    std::set<u64> m_managed_display_recording_layers{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM
 | 
			
		||||
@@ -10,9 +10,8 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
 | 
			
		||||
                                                               Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} {
 | 
			
		||||
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_)
 | 
			
		||||
    : ServiceFramework{system_, "appletAE"} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
 | 
			
		||||
@@ -37,8 +36,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called");
 | 
			
		||||
 | 
			
		||||
    if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
 | 
			
		||||
        *out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
 | 
			
		||||
            system, applet, process_handle.Get(), m_nvnflinger);
 | 
			
		||||
        *out_system_applet_proxy =
 | 
			
		||||
            std::make_shared<ISystemAppletProxy>(system, applet, process_handle.Get());
 | 
			
		||||
        R_SUCCEED();
 | 
			
		||||
    } else {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
@@ -53,8 +52,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called");
 | 
			
		||||
 | 
			
		||||
    if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
 | 
			
		||||
        *out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
 | 
			
		||||
            system, applet, process_handle.Get(), m_nvnflinger);
 | 
			
		||||
        *out_library_applet_proxy =
 | 
			
		||||
            std::make_shared<ILibraryAppletProxy>(system, applet, process_handle.Get());
 | 
			
		||||
        R_SUCCEED();
 | 
			
		||||
    } else {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
 
 | 
			
		||||
@@ -8,10 +8,6 @@
 | 
			
		||||
 | 
			
		||||
namespace Service {
 | 
			
		||||
 | 
			
		||||
namespace Nvnflinger {
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace AM {
 | 
			
		||||
 | 
			
		||||
struct Applet;
 | 
			
		||||
@@ -22,8 +18,7 @@ class ISystemAppletProxy;
 | 
			
		||||
class IAllSystemAppletProxiesService final
 | 
			
		||||
    : public ServiceFramework<IAllSystemAppletProxiesService> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IAllSystemAppletProxiesService(Core::System& system_,
 | 
			
		||||
                                            Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
    explicit IAllSystemAppletProxiesService(Core::System& system_);
 | 
			
		||||
    ~IAllSystemAppletProxiesService() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -40,7 +35,6 @@ private:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace AM
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,9 @@
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
 | 
			
		||||
                                     Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "IApplicationProxy"},
 | 
			
		||||
      m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
 | 
			
		||||
                                     Kernel::KProcess* process)
 | 
			
		||||
    : ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{
 | 
			
		||||
                                                                              std::move(applet)} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
 | 
			
		||||
@@ -77,8 +77,7 @@ Result IApplicationProxy::GetWindowController(
 | 
			
		||||
Result IApplicationProxy::GetSelfController(
 | 
			
		||||
    Out<SharedPointer<ISelfController>> out_self_controller) {
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called");
 | 
			
		||||
    *out_self_controller =
 | 
			
		||||
        std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
 | 
			
		||||
    *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ class IWindowController;
 | 
			
		||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
 | 
			
		||||
                               Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
                               Kernel::KProcess* process);
 | 
			
		||||
    ~IApplicationProxy();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -40,7 +40,6 @@ private:
 | 
			
		||||
        Out<SharedPointer<IApplicationFunctions>> out_application_functions);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Kernel::KProcess* const m_process;
 | 
			
		||||
    const std::shared_ptr<Applet> m_applet;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -10,9 +10,8 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
IApplicationProxyService::IApplicationProxyService(Core::System& system_,
 | 
			
		||||
                                                   Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} {
 | 
			
		||||
IApplicationProxyService::IApplicationProxyService(Core::System& system_)
 | 
			
		||||
    : ServiceFramework{system_, "appletOE"} {
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
 | 
			
		||||
    };
 | 
			
		||||
@@ -28,7 +27,7 @@ Result IApplicationProxyService::OpenApplicationProxy(
 | 
			
		||||
 | 
			
		||||
    if (const auto applet = this->GetAppletFromProcessId(pid)) {
 | 
			
		||||
        *out_application_proxy =
 | 
			
		||||
            std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger);
 | 
			
		||||
            std::make_shared<IApplicationProxy>(system, applet, process_handle.Get());
 | 
			
		||||
        R_SUCCEED();
 | 
			
		||||
    } else {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
 
 | 
			
		||||
@@ -8,10 +8,6 @@
 | 
			
		||||
 | 
			
		||||
namespace Service {
 | 
			
		||||
 | 
			
		||||
namespace Nvnflinger {
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace AM {
 | 
			
		||||
 | 
			
		||||
struct Applet;
 | 
			
		||||
@@ -19,7 +15,7 @@ class IApplicationProxy;
 | 
			
		||||
 | 
			
		||||
class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
    explicit IApplicationProxyService(Core::System& system_);
 | 
			
		||||
    ~IApplicationProxyService() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -28,7 +24,6 @@ private:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace AM
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_i
 | 
			
		||||
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
 | 
			
		||||
    Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
 | 
			
		||||
    LOG_WARNING(Service_AM, "(STUBBED) called");
 | 
			
		||||
    R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
 | 
			
		||||
    R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
 | 
			
		||||
                                                                    out_fbshare_layer_index));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -81,7 +81,7 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
 | 
			
		||||
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
 | 
			
		||||
    Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
 | 
			
		||||
    LOG_WARNING(Service_AM, "(STUBBED) called");
 | 
			
		||||
    R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
 | 
			
		||||
    R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
 | 
			
		||||
                                                                    out_fbshare_layer_index));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -93,7 +93,7 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
 | 
			
		||||
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
 | 
			
		||||
    Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
 | 
			
		||||
    LOG_WARNING(Service_AM, "(STUBBED) called");
 | 
			
		||||
    R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
 | 
			
		||||
    R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
 | 
			
		||||
                                                                    out_fbshare_layer_index));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -135,7 +135,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
 | 
			
		||||
    case LibraryAppletMode::AllForegroundInitiallyHidden:
 | 
			
		||||
        applet->hid_registration.EnableAppletToGetInput(false);
 | 
			
		||||
        applet->focus_state = FocusState::NotInFocus;
 | 
			
		||||
        applet->system_buffer_manager.SetWindowVisibility(false);
 | 
			
		||||
        applet->display_layer_manager.SetWindowVisibility(false);
 | 
			
		||||
        applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,10 +19,9 @@
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
 | 
			
		||||
                                         Kernel::KProcess* process,
 | 
			
		||||
                                         Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "ILibraryAppletProxy"},
 | 
			
		||||
      m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
 | 
			
		||||
                                         Kernel::KProcess* process)
 | 
			
		||||
    : ServiceFramework{system_, "ILibraryAppletProxy"}, m_process{process}, m_applet{
 | 
			
		||||
                                                                                std::move(applet)} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
 | 
			
		||||
@@ -83,8 +82,7 @@ Result ILibraryAppletProxy::GetWindowController(
 | 
			
		||||
Result ILibraryAppletProxy::GetSelfController(
 | 
			
		||||
    Out<SharedPointer<ISelfController>> out_self_controller) {
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called");
 | 
			
		||||
    *out_self_controller =
 | 
			
		||||
        std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
 | 
			
		||||
    *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ class IWindowController;
 | 
			
		||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
 | 
			
		||||
                                 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
                                 Kernel::KProcess* process);
 | 
			
		||||
    ~ILibraryAppletProxy();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -47,7 +47,6 @@ private:
 | 
			
		||||
    Result GetGlobalStateController(
 | 
			
		||||
        Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Kernel::KProcess* const m_process;
 | 
			
		||||
    const std::shared_ptr<Applet> m_applet;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,9 @@
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
 | 
			
		||||
                                 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "ISelfController"},
 | 
			
		||||
      m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
 | 
			
		||||
                                 Kernel::KProcess* process)
 | 
			
		||||
    : ServiceFramework{system_, "ISelfController"}, m_process{process}, m_applet{
 | 
			
		||||
                                                                            std::move(applet)} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, D<&ISelfController::Exit>, "Exit"},
 | 
			
		||||
@@ -72,9 +72,16 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
 | 
			
		||||
    // clang-format on
 | 
			
		||||
 | 
			
		||||
    RegisterHandlers(functions);
 | 
			
		||||
 | 
			
		||||
    std::scoped_lock lk{m_applet->lock};
 | 
			
		||||
    m_applet->display_layer_manager.Initialize(system, m_process, m_applet->applet_id,
 | 
			
		||||
                                               m_applet->library_applet_mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ISelfController::~ISelfController() = default;
 | 
			
		||||
ISelfController::~ISelfController() {
 | 
			
		||||
    std::scoped_lock lk{m_applet->lock};
 | 
			
		||||
    m_applet->display_layer_manager.Finalize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISelfController::Exit() {
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called");
 | 
			
		||||
@@ -212,48 +219,42 @@ Result ISelfController::SetAlbumImageOrientation(
 | 
			
		||||
 | 
			
		||||
Result ISelfController::IsSystemBufferSharingEnabled() {
 | 
			
		||||
    LOG_INFO(Service_AM, "called");
 | 
			
		||||
    R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize(
 | 
			
		||||
        &m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode));
 | 
			
		||||
    R_THROW(VI::ResultOperationFailed);
 | 
			
		||||
 | 
			
		||||
    std::scoped_lock lk{m_applet->lock};
 | 
			
		||||
    R_RETURN(m_applet->display_layer_manager.IsSystemBufferSharingEnabled());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) {
 | 
			
		||||
    LOG_WARNING(Service_AM, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
    R_TRY(this->IsSystemBufferSharingEnabled());
 | 
			
		||||
    LOG_INFO(Service_AM, "called");
 | 
			
		||||
 | 
			
		||||
    u64 layer_id;
 | 
			
		||||
    m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
 | 
			
		||||
    std::scoped_lock lk{m_applet->lock};
 | 
			
		||||
    R_RETURN(m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) {
 | 
			
		||||
    LOG_INFO(Service_AM, "(STUBBED) called");
 | 
			
		||||
    LOG_INFO(Service_AM, "called");
 | 
			
		||||
 | 
			
		||||
    R_TRY(this->IsSystemBufferSharingEnabled());
 | 
			
		||||
 | 
			
		||||
    m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
    std::scoped_lock lk{m_applet->lock};
 | 
			
		||||
    R_RETURN(
 | 
			
		||||
        m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) {
 | 
			
		||||
    LOG_INFO(Service_AM, "called");
 | 
			
		||||
 | 
			
		||||
    m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
 | 
			
		||||
    m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id);
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
    std::scoped_lock lk{m_applet->lock};
 | 
			
		||||
    R_RETURN(m_applet->display_layer_manager.CreateManagedDisplayLayer(out_layer_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
 | 
			
		||||
                                                           Out<u64> out_recording_layer_id) {
 | 
			
		||||
    LOG_WARNING(Service_AM, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
    m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
 | 
			
		||||
    m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id,
 | 
			
		||||
                                                                      out_recording_layer_id);
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
    std::scoped_lock lk{m_applet->lock};
 | 
			
		||||
    R_RETURN(m_applet->display_layer_manager.CreateManagedDisplaySeparableLayer(
 | 
			
		||||
        out_layer_id, out_recording_layer_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISelfController::SetHandlesRequestToDisplay(bool enable) {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ struct Applet;
 | 
			
		||||
class ISelfController final : public ServiceFramework<ISelfController> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
 | 
			
		||||
                             Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
                             Kernel::KProcess* process);
 | 
			
		||||
    ~ISelfController() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -64,7 +64,6 @@ private:
 | 
			
		||||
    Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
 | 
			
		||||
    Result SetRecordVolumeMuted(bool muted);
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Kernel::KProcess* const m_process;
 | 
			
		||||
    const std::shared_ptr<Applet> m_applet;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -19,10 +19,9 @@
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
 | 
			
		||||
                                       Kernel::KProcess* process,
 | 
			
		||||
                                       Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "ISystemAppletProxy"},
 | 
			
		||||
      m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
 | 
			
		||||
                                       Kernel::KProcess* process)
 | 
			
		||||
    : ServiceFramework{system_, "ISystemAppletProxy"}, m_process{process}, m_applet{
 | 
			
		||||
                                                                               std::move(applet)} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
 | 
			
		||||
@@ -83,8 +82,7 @@ Result ISystemAppletProxy::GetWindowController(
 | 
			
		||||
Result ISystemAppletProxy::GetSelfController(
 | 
			
		||||
    Out<SharedPointer<ISelfController>> out_self_controller) {
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called");
 | 
			
		||||
    *out_self_controller =
 | 
			
		||||
        std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
 | 
			
		||||
    *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ class IWindowController;
 | 
			
		||||
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
 | 
			
		||||
                                Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
                                Kernel::KProcess* process);
 | 
			
		||||
    ~ISystemAppletProxy();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -46,7 +46,6 @@ private:
 | 
			
		||||
    Result GetGlobalStateController(
 | 
			
		||||
        Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Kernel::KProcess* const m_process;
 | 
			
		||||
    const std::shared_ptr<Applet> m_applet;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ Result IWindowController::RejectToChangeIntoBackground() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IWindowController::SetAppletWindowVisibility(bool visible) {
 | 
			
		||||
    m_applet->system_buffer_manager.SetWindowVisibility(visible);
 | 
			
		||||
    m_applet->display_layer_manager.SetWindowVisibility(visible);
 | 
			
		||||
    m_applet->hid_registration.EnableAppletToGetInput(visible);
 | 
			
		||||
 | 
			
		||||
    if (visible) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,80 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/am/system_buffer_manager.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
 | 
			
		||||
#include "core/hle/service/vi/vi_results.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
SystemBufferManager::SystemBufferManager() = default;
 | 
			
		||||
 | 
			
		||||
SystemBufferManager::~SystemBufferManager() {
 | 
			
		||||
    if (!m_nvnflinger) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clean up shared layers.
 | 
			
		||||
    if (m_buffer_sharing_enabled) {
 | 
			
		||||
        m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
 | 
			
		||||
                                     AppletId applet_id, LibraryAppletMode mode) {
 | 
			
		||||
    if (m_nvnflinger) {
 | 
			
		||||
        return m_buffer_sharing_enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_process = process;
 | 
			
		||||
    m_nvnflinger = nvnflinger;
 | 
			
		||||
    m_buffer_sharing_enabled = false;
 | 
			
		||||
    m_system_shared_buffer_id = 0;
 | 
			
		||||
    m_system_shared_layer_id = 0;
 | 
			
		||||
 | 
			
		||||
    if (applet_id <= AppletId::Application) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
 | 
			
		||||
    if (mode == LibraryAppletMode::PartialForeground ||
 | 
			
		||||
        mode == LibraryAppletMode::PartialForegroundIndirectDisplay) {
 | 
			
		||||
        blending = Nvnflinger::LayerBlending::Coverage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
 | 
			
		||||
    const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
 | 
			
		||||
        m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
 | 
			
		||||
 | 
			
		||||
    if (res.IsSuccess()) {
 | 
			
		||||
        m_buffer_sharing_enabled = true;
 | 
			
		||||
        m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m_buffer_sharing_enabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemBufferManager::SetWindowVisibility(bool visible) {
 | 
			
		||||
    if (m_visible == visible) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_visible = visible;
 | 
			
		||||
 | 
			
		||||
    if (m_nvnflinger) {
 | 
			
		||||
        m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
 | 
			
		||||
                                                     s32* out_fbshare_layer_index) {
 | 
			
		||||
    if (!m_buffer_sharing_enabled) {
 | 
			
		||||
        return VI::ResultPermissionDenied;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written,
 | 
			
		||||
                                                                           out_fbshare_layer_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM
 | 
			
		||||
@@ -1,52 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <set>
 | 
			
		||||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/am/am_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
class KProcess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
union Result;
 | 
			
		||||
 | 
			
		||||
namespace Service::AM {
 | 
			
		||||
 | 
			
		||||
class SystemBufferManager {
 | 
			
		||||
public:
 | 
			
		||||
    SystemBufferManager();
 | 
			
		||||
    ~SystemBufferManager();
 | 
			
		||||
 | 
			
		||||
    bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id,
 | 
			
		||||
                    LibraryAppletMode mode);
 | 
			
		||||
 | 
			
		||||
    void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
 | 
			
		||||
                                    u64* out_system_shared_layer_id) {
 | 
			
		||||
        *out_system_shared_buffer_id = m_system_shared_buffer_id;
 | 
			
		||||
        *out_system_shared_layer_id = m_system_shared_layer_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SetWindowVisibility(bool visible);
 | 
			
		||||
 | 
			
		||||
    Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Kernel::KProcess* m_process{};
 | 
			
		||||
    Nvnflinger::Nvnflinger* m_nvnflinger{};
 | 
			
		||||
    bool m_buffer_sharing_enabled{};
 | 
			
		||||
    bool m_visible{true};
 | 
			
		||||
    u64 m_system_shared_buffer_id{};
 | 
			
		||||
    u64 m_system_shared_layer_id{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM
 | 
			
		||||
@@ -42,7 +42,7 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) {
 | 
			
		||||
    module.service_context.CloseEvent(event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
 | 
			
		||||
void LoopProcess(Core::System& system) {
 | 
			
		||||
    auto server_manager = std::make_unique<ServerManager>(system);
 | 
			
		||||
    auto module = std::make_shared<Module>(system);
 | 
			
		||||
    const auto NvdrvInterfaceFactoryForApplication = [&, module] {
 | 
			
		||||
@@ -62,7 +62,6 @@ void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
 | 
			
		||||
    server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules);
 | 
			
		||||
    server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting);
 | 
			
		||||
    server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));
 | 
			
		||||
    nvnflinger.SetNVDrvInstance(module);
 | 
			
		||||
    ServerManager::RunServer(std::move(server_manager));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,13 +10,11 @@
 | 
			
		||||
#include <span>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/service/kernel_helpers.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/core/container.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/nvdata.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/ui/fence.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
@@ -27,10 +25,6 @@ namespace Kernel {
 | 
			
		||||
class KEvent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvidia {
 | 
			
		||||
 | 
			
		||||
namespace NvCore {
 | 
			
		||||
@@ -99,7 +93,6 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class EventInterface;
 | 
			
		||||
    friend class Service::Nvnflinger::Nvnflinger;
 | 
			
		||||
 | 
			
		||||
    /// Manages syncpoints on the host
 | 
			
		||||
    NvCore::Container container;
 | 
			
		||||
@@ -118,6 +111,6 @@ private:
 | 
			
		||||
    std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
 | 
			
		||||
void LoopProcess(Core::System& system);
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvidia
 | 
			
		||||
 
 | 
			
		||||
@@ -263,8 +263,10 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char*
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NVDRV::~NVDRV() {
 | 
			
		||||
    auto& container = nvdrv->GetContainer();
 | 
			
		||||
    container.CloseSession(session_id);
 | 
			
		||||
    if (is_initialized) {
 | 
			
		||||
        auto& container = nvdrv->GetContainer();
 | 
			
		||||
        container.CloseSession(session_id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvidia
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,10 @@ public:
 | 
			
		||||
    explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name);
 | 
			
		||||
    ~NVDRV() override;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Module> GetModule() const {
 | 
			
		||||
        return nvdrv;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void Open(HLERequestContext& ctx);
 | 
			
		||||
    void Ioctl1(HLERequestContext& ctx);
 | 
			
		||||
 
 | 
			
		||||
@@ -20,29 +20,12 @@ class HLERequestContext;
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
 | 
			
		||||
enum class TransactionId {
 | 
			
		||||
    RequestBuffer = 1,
 | 
			
		||||
    SetBufferCount = 2,
 | 
			
		||||
    DequeueBuffer = 3,
 | 
			
		||||
    DetachBuffer = 4,
 | 
			
		||||
    DetachNextBuffer = 5,
 | 
			
		||||
    AttachBuffer = 6,
 | 
			
		||||
    QueueBuffer = 7,
 | 
			
		||||
    CancelBuffer = 8,
 | 
			
		||||
    Query = 9,
 | 
			
		||||
    Connect = 10,
 | 
			
		||||
    Disconnect = 11,
 | 
			
		||||
    AllocateBuffers = 13,
 | 
			
		||||
    SetPreallocatedBuffer = 14,
 | 
			
		||||
    GetBufferHistory = 17,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class IBinder {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~IBinder() = default;
 | 
			
		||||
    virtual void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data,
 | 
			
		||||
                          std::span<u8> parcel_reply) = 0;
 | 
			
		||||
    virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
 | 
			
		||||
    virtual void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
 | 
			
		||||
                          u32 flags) = 0;
 | 
			
		||||
    virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::android
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
 | 
			
		||||
BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_)
 | 
			
		||||
BufferItemConsumer::BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer_)
 | 
			
		||||
    : ConsumerBase{std::move(consumer_)} {}
 | 
			
		||||
 | 
			
		||||
Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ class BufferItem;
 | 
			
		||||
 | 
			
		||||
class BufferItemConsumer final : public ConsumerBase {
 | 
			
		||||
public:
 | 
			
		||||
    explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer);
 | 
			
		||||
    explicit BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer);
 | 
			
		||||
    Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
 | 
			
		||||
                         bool wait_for_fence = true);
 | 
			
		||||
    Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,13 @@
 | 
			
		||||
// Parts of this implementation were based on:
 | 
			
		||||
// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_item.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/parcel.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/producer_listener.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
 | 
			
		||||
@@ -254,4 +255,77 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
 | 
			
		||||
    return Status::NoError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BufferQueueConsumer::Transact(u32 code, std::span<const u8> parcel_data,
 | 
			
		||||
                                   std::span<u8> parcel_reply, u32 flags) {
 | 
			
		||||
    // Values used by BnGraphicBufferConsumer onTransact
 | 
			
		||||
    enum class TransactionId {
 | 
			
		||||
        AcquireBuffer = 1,
 | 
			
		||||
        DetachBuffer = 2,
 | 
			
		||||
        AttachBuffer = 3,
 | 
			
		||||
        ReleaseBuffer = 4,
 | 
			
		||||
        ConsumerConnect = 5,
 | 
			
		||||
        ConsumerDisconnect = 6,
 | 
			
		||||
        GetReleasedBuffers = 7,
 | 
			
		||||
        SetDefaultBufferSize = 8,
 | 
			
		||||
        SetDefaultMaxBufferCount = 9,
 | 
			
		||||
        DisableAsyncBuffer = 10,
 | 
			
		||||
        SetMaxAcquiredBufferCount = 11,
 | 
			
		||||
        SetConsumerName = 12,
 | 
			
		||||
        SetDefaultBufferFormat = 13,
 | 
			
		||||
        SetConsumerUsageBits = 14,
 | 
			
		||||
        SetTransformHint = 15,
 | 
			
		||||
        GetSidebandStream = 16,
 | 
			
		||||
        Unknown18 = 18,
 | 
			
		||||
        Unknown20 = 20,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Status status{Status::NoError};
 | 
			
		||||
    InputParcel parcel_in{parcel_data};
 | 
			
		||||
    OutputParcel parcel_out{};
 | 
			
		||||
 | 
			
		||||
    switch (static_cast<TransactionId>(code)) {
 | 
			
		||||
    case TransactionId::AcquireBuffer: {
 | 
			
		||||
        BufferItem item;
 | 
			
		||||
        const s64 present_when = parcel_in.Read<s64>();
 | 
			
		||||
 | 
			
		||||
        status = AcquireBuffer(&item, std::chrono::nanoseconds{present_when});
 | 
			
		||||
 | 
			
		||||
        // TODO: can't write this directly, needs a flattener for the sp<GraphicBuffer>
 | 
			
		||||
        // parcel_out.WriteFlattened(item);
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
    }
 | 
			
		||||
    case TransactionId::ReleaseBuffer: {
 | 
			
		||||
        const s32 slot = parcel_in.Read<s32>();
 | 
			
		||||
        const u64 frame_number = parcel_in.Read<u64>();
 | 
			
		||||
        const auto release_fence = parcel_in.ReadFlattened<Fence>();
 | 
			
		||||
 | 
			
		||||
        status = ReleaseBuffer(slot, frame_number, release_fence);
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case TransactionId::GetReleasedBuffers: {
 | 
			
		||||
        u64 slot_mask = 0;
 | 
			
		||||
 | 
			
		||||
        status = GetReleasedBuffers(&slot_mask);
 | 
			
		||||
 | 
			
		||||
        parcel_out.Write(slot_mask);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
        ASSERT_MSG(false, "called, code={} flags={}", code, flags);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    parcel_out.Write(status);
 | 
			
		||||
 | 
			
		||||
    const auto serialized = parcel_out.Serialize();
 | 
			
		||||
    std::memcpy(parcel_reply.data(), serialized.data(),
 | 
			
		||||
                std::min(parcel_reply.size(), serialized.size()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Kernel::KReadableEvent* BufferQueueConsumer::GetNativeHandle(u32 type_id) {
 | 
			
		||||
    ASSERT_MSG(false, "called, type_id={}", type_id);
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::android
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/binder.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/status.h"
 | 
			
		||||
 | 
			
		||||
@@ -19,10 +20,10 @@ class BufferItem;
 | 
			
		||||
class BufferQueueCore;
 | 
			
		||||
class IConsumerListener;
 | 
			
		||||
 | 
			
		||||
class BufferQueueConsumer final {
 | 
			
		||||
class BufferQueueConsumer final : public IBinder {
 | 
			
		||||
public:
 | 
			
		||||
    explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
 | 
			
		||||
    ~BufferQueueConsumer();
 | 
			
		||||
    ~BufferQueueConsumer() override;
 | 
			
		||||
 | 
			
		||||
    Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
 | 
			
		||||
    Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
 | 
			
		||||
@@ -30,6 +31,11 @@ public:
 | 
			
		||||
    Status Disconnect();
 | 
			
		||||
    Status GetReleasedBuffers(u64* out_slot_mask);
 | 
			
		||||
 | 
			
		||||
    void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
 | 
			
		||||
                  u32 flags) override;
 | 
			
		||||
 | 
			
		||||
    Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::shared_ptr<BufferQueueCore> core;
 | 
			
		||||
    BufferQueueDefs::SlotsType& slots;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,9 @@
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/kernel/k_event.h"
 | 
			
		||||
#include "core/hle/kernel/k_readable_event.h"
 | 
			
		||||
#include "core/hle/kernel/kernel.h"
 | 
			
		||||
#include "core/hle/service/hle_ipc.h"
 | 
			
		||||
#include "core/hle/service/kernel_helpers.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
 | 
			
		||||
@@ -19,7 +16,6 @@
 | 
			
		||||
#include "core/hle/service/nvnflinger/parcel.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/window.h"
 | 
			
		||||
#include "core/hle/service/vi/vi.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
 | 
			
		||||
@@ -807,13 +803,31 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
 | 
			
		||||
    return Status::NoError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<const u8> parcel_data,
 | 
			
		||||
                                   std::span<u8> parcel_reply) {
 | 
			
		||||
void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
 | 
			
		||||
                                   std::span<u8> parcel_reply, u32 flags) {
 | 
			
		||||
    // Values used by BnGraphicBufferProducer onTransact
 | 
			
		||||
    enum class TransactionId {
 | 
			
		||||
        RequestBuffer = 1,
 | 
			
		||||
        SetBufferCount = 2,
 | 
			
		||||
        DequeueBuffer = 3,
 | 
			
		||||
        DetachBuffer = 4,
 | 
			
		||||
        DetachNextBuffer = 5,
 | 
			
		||||
        AttachBuffer = 6,
 | 
			
		||||
        QueueBuffer = 7,
 | 
			
		||||
        CancelBuffer = 8,
 | 
			
		||||
        Query = 9,
 | 
			
		||||
        Connect = 10,
 | 
			
		||||
        Disconnect = 11,
 | 
			
		||||
        AllocateBuffers = 13,
 | 
			
		||||
        SetPreallocatedBuffer = 14,
 | 
			
		||||
        GetBufferHistory = 17,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Status status{Status::NoError};
 | 
			
		||||
    InputParcel parcel_in{parcel_data};
 | 
			
		||||
    OutputParcel parcel_out{};
 | 
			
		||||
 | 
			
		||||
    switch (code) {
 | 
			
		||||
    switch (static_cast<TransactionId>(code)) {
 | 
			
		||||
    case TransactionId::Connect: {
 | 
			
		||||
        const auto enable_listener = parcel_in.Read<bool>();
 | 
			
		||||
        const auto api = parcel_in.Read<NativeWindowApi>();
 | 
			
		||||
@@ -923,8 +937,8 @@ void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<cons
 | 
			
		||||
                std::min(parcel_reply.size(), serialized.size()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() {
 | 
			
		||||
    return buffer_wait_event->GetReadableEvent();
 | 
			
		||||
Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
 | 
			
		||||
    return &buffer_wait_event->GetReadableEvent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::android
 | 
			
		||||
 
 | 
			
		||||
@@ -45,12 +45,12 @@ public:
 | 
			
		||||
    explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
 | 
			
		||||
                                 std::shared_ptr<BufferQueueCore> buffer_queue_core_,
 | 
			
		||||
                                 Service::Nvidia::NvCore::NvMap& nvmap_);
 | 
			
		||||
    ~BufferQueueProducer();
 | 
			
		||||
    ~BufferQueueProducer() override;
 | 
			
		||||
 | 
			
		||||
    void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data,
 | 
			
		||||
                  std::span<u8> parcel_reply) override;
 | 
			
		||||
    void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
 | 
			
		||||
                  u32 flags) override;
 | 
			
		||||
 | 
			
		||||
    Kernel::KReadableEvent& GetNativeHandle() override;
 | 
			
		||||
    Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
 | 
			
		||||
ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_)
 | 
			
		||||
ConsumerBase::ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_)
 | 
			
		||||
    : consumer{std::move(consumer_)} {}
 | 
			
		||||
 | 
			
		||||
ConsumerBase::~ConsumerBase() {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ public:
 | 
			
		||||
    void Abandon();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
 | 
			
		||||
    explicit ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_);
 | 
			
		||||
    ~ConsumerBase() override;
 | 
			
		||||
 | 
			
		||||
    void OnFrameAvailable(const BufferItem& item) override;
 | 
			
		||||
@@ -54,7 +54,7 @@ protected:
 | 
			
		||||
 | 
			
		||||
    bool is_abandoned{};
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<BufferQueueConsumer> consumer;
 | 
			
		||||
    std::shared_ptr<BufferQueueConsumer> consumer;
 | 
			
		||||
 | 
			
		||||
    mutable std::mutex mutex;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								src/core/hle/service/nvnflinger/display.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/core/hle/service/nvnflinger/display.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <list>
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hwc_layer.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
struct Layer {
 | 
			
		||||
    explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
 | 
			
		||||
                   s32 consumer_id_)
 | 
			
		||||
        : buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
 | 
			
		||||
          blending(LayerBlending::None), visible(true) {}
 | 
			
		||||
    ~Layer() {
 | 
			
		||||
        buffer_item_consumer->Abandon();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer;
 | 
			
		||||
    s32 consumer_id;
 | 
			
		||||
    LayerBlending blending;
 | 
			
		||||
    bool visible;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LayerStack {
 | 
			
		||||
    std::list<Layer> layers;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Display {
 | 
			
		||||
    explicit Display(u64 id_) {
 | 
			
		||||
        id = id_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Layer* FindLayer(s32 consumer_id) {
 | 
			
		||||
        for (auto& layer : stack.layers) {
 | 
			
		||||
            if (layer.consumer_id == consumer_id) {
 | 
			
		||||
                return &layer;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool HasLayers() {
 | 
			
		||||
        return !stack.layers.empty();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u64 id;
 | 
			
		||||
    LayerStack stack;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
@@ -10,8 +10,6 @@
 | 
			
		||||
#include "core/hle/service/nvnflinger/hardware_composer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hwc_layer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
 | 
			
		||||
#include "core/hle/service/vi/display/vi_display.h"
 | 
			
		||||
#include "core/hle/service/vi/layer/vi_layer.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +42,7 @@ s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) {
 | 
			
		||||
HardwareComposer::HardwareComposer() = default;
 | 
			
		||||
HardwareComposer::~HardwareComposer() = default;
 | 
			
		||||
 | 
			
		||||
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
 | 
			
		||||
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
 | 
			
		||||
                                    Nvidia::Devices::nvdisp_disp0& nvdisp) {
 | 
			
		||||
    boost::container::small_vector<HwcLayer, 2> composition_stack;
 | 
			
		||||
 | 
			
		||||
@@ -56,12 +54,11 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
 | 
			
		||||
    bool has_acquired_buffer{};
 | 
			
		||||
 | 
			
		||||
    // Acquire all necessary framebuffers.
 | 
			
		||||
    for (size_t i = 0; i < display.GetNumLayers(); i++) {
 | 
			
		||||
        auto& layer = display.GetLayer(i);
 | 
			
		||||
        auto layer_id = layer.GetLayerId();
 | 
			
		||||
    for (auto& layer : display.stack.layers) {
 | 
			
		||||
        auto consumer_id = layer.consumer_id;
 | 
			
		||||
 | 
			
		||||
        // Try to fetch the framebuffer (either new or stale).
 | 
			
		||||
        const auto result = this->CacheFramebufferLocked(layer, layer_id);
 | 
			
		||||
        const auto result = this->CacheFramebufferLocked(layer, consumer_id);
 | 
			
		||||
 | 
			
		||||
        // If we failed, skip this layer.
 | 
			
		||||
        if (result == CacheStatus::NoBufferAvailable) {
 | 
			
		||||
@@ -73,24 +70,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
 | 
			
		||||
            has_acquired_buffer = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const auto& buffer = m_framebuffers[layer_id];
 | 
			
		||||
        const auto& buffer = m_framebuffers[consumer_id];
 | 
			
		||||
        const auto& item = buffer.item;
 | 
			
		||||
        const auto& igbp_buffer = *item.graphic_buffer;
 | 
			
		||||
 | 
			
		||||
        // TODO: get proper Z-index from layer
 | 
			
		||||
        composition_stack.emplace_back(HwcLayer{
 | 
			
		||||
            .buffer_handle = igbp_buffer.BufferId(),
 | 
			
		||||
            .offset = igbp_buffer.Offset(),
 | 
			
		||||
            .format = igbp_buffer.ExternalFormat(),
 | 
			
		||||
            .width = igbp_buffer.Width(),
 | 
			
		||||
            .height = igbp_buffer.Height(),
 | 
			
		||||
            .stride = igbp_buffer.Stride(),
 | 
			
		||||
            .z_index = 0,
 | 
			
		||||
            .blending = layer.GetBlending(),
 | 
			
		||||
            .transform = static_cast<android::BufferTransformFlags>(item.transform),
 | 
			
		||||
            .crop_rect = item.crop,
 | 
			
		||||
            .acquire_fence = item.fence,
 | 
			
		||||
        });
 | 
			
		||||
        if (layer.visible) {
 | 
			
		||||
            composition_stack.emplace_back(HwcLayer{
 | 
			
		||||
                .buffer_handle = igbp_buffer.BufferId(),
 | 
			
		||||
                .offset = igbp_buffer.Offset(),
 | 
			
		||||
                .format = igbp_buffer.ExternalFormat(),
 | 
			
		||||
                .width = igbp_buffer.Width(),
 | 
			
		||||
                .height = igbp_buffer.Height(),
 | 
			
		||||
                .stride = igbp_buffer.Stride(),
 | 
			
		||||
                .z_index = 0,
 | 
			
		||||
                .blending = layer.blending,
 | 
			
		||||
                .transform = static_cast<android::BufferTransformFlags>(item.transform),
 | 
			
		||||
                .crop_rect = item.crop,
 | 
			
		||||
                .acquire_fence = item.fence,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We need to compose again either before this frame is supposed to
 | 
			
		||||
        // be released, or exactly on the vsync period it should be released.
 | 
			
		||||
@@ -138,7 +137,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
 | 
			
		||||
        if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
 | 
			
		||||
            // TODO: support release fence
 | 
			
		||||
            // This is needed to prevent screen tearing
 | 
			
		||||
            layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
 | 
			
		||||
            layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
 | 
			
		||||
            framebuffer.is_acquired = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -146,26 +145,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
 | 
			
		||||
    return frame_advance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
 | 
			
		||||
    // Check if we are tracking a slot with this layer_id.
 | 
			
		||||
    const auto it = m_framebuffers.find(layer_id);
 | 
			
		||||
void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) {
 | 
			
		||||
    // Check if we are tracking a slot with this consumer_id.
 | 
			
		||||
    const auto it = m_framebuffers.find(consumer_id);
 | 
			
		||||
    if (it == m_framebuffers.end()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Try to release the buffer item.
 | 
			
		||||
    auto* const layer = display.FindLayer(layer_id);
 | 
			
		||||
    auto* const layer = display.FindLayer(consumer_id);
 | 
			
		||||
    if (layer && it->second.is_acquired) {
 | 
			
		||||
        layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence());
 | 
			
		||||
        layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Erase the slot.
 | 
			
		||||
    m_framebuffers.erase(it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) {
 | 
			
		||||
bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer) {
 | 
			
		||||
    // Attempt the update.
 | 
			
		||||
    const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false);
 | 
			
		||||
    const auto status = layer.buffer_item_consumer->AcquireBuffer(&framebuffer.item, {}, false);
 | 
			
		||||
    if (status != android::Status::NoError) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -178,10 +177,10 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer,
 | 
			
		||||
                                                                       LayerId layer_id) {
 | 
			
		||||
HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(Layer& layer,
 | 
			
		||||
                                                                       ConsumerId consumer_id) {
 | 
			
		||||
    // Check if this framebuffer is already present.
 | 
			
		||||
    const auto it = m_framebuffers.find(layer_id);
 | 
			
		||||
    const auto it = m_framebuffers.find(consumer_id);
 | 
			
		||||
    if (it != m_framebuffers.end()) {
 | 
			
		||||
        // If it's currently still acquired, we are done.
 | 
			
		||||
        if (it->second.is_acquired) {
 | 
			
		||||
@@ -203,7 +202,7 @@ HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer
 | 
			
		||||
 | 
			
		||||
    if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
 | 
			
		||||
        // Move the buffer item into a new slot.
 | 
			
		||||
        m_framebuffers.emplace(layer_id, std::move(framebuffer));
 | 
			
		||||
        m_framebuffers.emplace(consumer_id, std::move(framebuffer));
 | 
			
		||||
 | 
			
		||||
        // We succeeded.
 | 
			
		||||
        return CacheStatus::BufferAcquired;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,35 +3,29 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <boost/container/flat_map.hpp>
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_item.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/display.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvidia::Devices {
 | 
			
		||||
class nvdisp_disp0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
class Display;
 | 
			
		||||
class Layer;
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
using LayerId = u64;
 | 
			
		||||
using ConsumerId = s32;
 | 
			
		||||
 | 
			
		||||
class HardwareComposer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit HardwareComposer();
 | 
			
		||||
    ~HardwareComposer();
 | 
			
		||||
 | 
			
		||||
    u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
 | 
			
		||||
    u32 ComposeLocked(f32* out_speed_scale, Display& display,
 | 
			
		||||
                      Nvidia::Devices::nvdisp_disp0& nvdisp);
 | 
			
		||||
    void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
 | 
			
		||||
    void RemoveLayerLocked(Display& display, ConsumerId consumer_id);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // TODO: do we want to track frame number in vi instead?
 | 
			
		||||
    u64 m_frame_number{0};
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -49,11 +43,11 @@ private:
 | 
			
		||||
        CachedBufferReused,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{};
 | 
			
		||||
    boost::container::flat_map<ConsumerId, Framebuffer> m_framebuffers{};
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer);
 | 
			
		||||
    CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id);
 | 
			
		||||
    bool TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer);
 | 
			
		||||
    CacheStatus CacheFramebufferLocked(Layer& layer, ConsumerId consumer_id);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 
 | 
			
		||||
@@ -3,13 +3,16 @@
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/cmif_serialization.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/binder.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hos_binder_driver.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
 | 
			
		||||
#include "core/hle/service/vi/hos_binder_driver.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server)
 | 
			
		||||
    : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server) {
 | 
			
		||||
IHOSBinderDriver::IHOSBinderDriver(Core::System& system_,
 | 
			
		||||
                                   std::shared_ptr<HosBinderDriverServer> server,
 | 
			
		||||
                                   std::shared_ptr<SurfaceFlinger> surface_flinger)
 | 
			
		||||
    : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server),
 | 
			
		||||
      m_surface_flinger(surface_flinger) {
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, C<&IHOSBinderDriver::TransactParcel>, "TransactParcel"},
 | 
			
		||||
        {1, C<&IHOSBinderDriver::AdjustRefcount>, "AdjustRefcount"},
 | 
			
		||||
@@ -21,13 +24,18 @@ IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderD
 | 
			
		||||
 | 
			
		||||
IHOSBinderDriver::~IHOSBinderDriver() = default;
 | 
			
		||||
 | 
			
		||||
Result IHOSBinderDriver::TransactParcel(s32 binder_id, android::TransactionId transaction_id,
 | 
			
		||||
Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id,
 | 
			
		||||
                                        InBuffer<BufferAttr_HipcMapAlias> parcel_data,
 | 
			
		||||
                                        OutBuffer<BufferAttr_HipcMapAlias> parcel_reply,
 | 
			
		||||
                                        u32 flags) {
 | 
			
		||||
    LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id,
 | 
			
		||||
              flags);
 | 
			
		||||
    m_server.TryGetProducer(binder_id)->Transact(transaction_id, flags, parcel_data, parcel_reply);
 | 
			
		||||
 | 
			
		||||
    const auto binder = m_server->TryGetBinder(binder_id);
 | 
			
		||||
    R_SUCCEED_IF(binder == nullptr);
 | 
			
		||||
 | 
			
		||||
    binder->Transact(transaction_id, parcel_data, parcel_reply, flags);
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -39,15 +47,20 @@ Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) {
 | 
			
		||||
Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id,
 | 
			
		||||
                                         OutCopyHandle<Kernel::KReadableEvent> out_handle) {
 | 
			
		||||
    LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id);
 | 
			
		||||
    *out_handle = &m_server.TryGetProducer(binder_id)->GetNativeHandle();
 | 
			
		||||
 | 
			
		||||
    const auto binder = m_server->TryGetBinder(binder_id);
 | 
			
		||||
    R_UNLESS(binder != nullptr, ResultUnknown);
 | 
			
		||||
 | 
			
		||||
    *out_handle = binder->GetNativeHandle(type_id);
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id,
 | 
			
		||||
Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, u32 transaction_id,
 | 
			
		||||
                                            InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
 | 
			
		||||
                                            OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply,
 | 
			
		||||
                                            u32 flags) {
 | 
			
		||||
    R_RETURN(this->TransactParcel(binder_id, transaction_id, parcel_data, parcel_reply, flags));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
@@ -2,29 +2,45 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/cmif_types.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/binder.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
class KReadableEvent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
class SurfaceFlinger;
 | 
			
		||||
 | 
			
		||||
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server);
 | 
			
		||||
    explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server,
 | 
			
		||||
                              std::shared_ptr<SurfaceFlinger> surface_flinger);
 | 
			
		||||
    ~IHOSBinderDriver() override;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<SurfaceFlinger> GetSurfaceFlinger() {
 | 
			
		||||
        return m_surface_flinger;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<HosBinderDriverServer> GetServer() {
 | 
			
		||||
        return m_server;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Result TransactParcel(s32 binder_id, android::TransactionId transaction_id,
 | 
			
		||||
    Result TransactParcel(s32 binder_id, u32 transaction_id,
 | 
			
		||||
                          InBuffer<BufferAttr_HipcMapAlias> parcel_data,
 | 
			
		||||
                          OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags);
 | 
			
		||||
    Result AdjustRefcount(s32 binder_id, s32 addval, s32 type);
 | 
			
		||||
    Result GetNativeHandle(s32 binder_id, u32 type_id,
 | 
			
		||||
                           OutCopyHandle<Kernel::KReadableEvent> out_handle);
 | 
			
		||||
    Result TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id,
 | 
			
		||||
    Result TransactParcelAuto(s32 binder_id, u32 transaction_id,
 | 
			
		||||
                              InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
 | 
			
		||||
                              OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& m_server;
 | 
			
		||||
    const std::shared_ptr<HosBinderDriverServer> m_server;
 | 
			
		||||
    const std::shared_ptr<SurfaceFlinger> m_surface_flinger;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
@@ -8,26 +8,30 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
HosBinderDriverServer::HosBinderDriverServer(Core::System& system_)
 | 
			
		||||
    : service_context(system_, "HosBinderDriverServer") {}
 | 
			
		||||
HosBinderDriverServer::HosBinderDriverServer() = default;
 | 
			
		||||
HosBinderDriverServer::~HosBinderDriverServer() = default;
 | 
			
		||||
 | 
			
		||||
HosBinderDriverServer::~HosBinderDriverServer() {}
 | 
			
		||||
 | 
			
		||||
u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) {
 | 
			
		||||
s32 HosBinderDriverServer::RegisterBinder(std::shared_ptr<android::IBinder>&& binder) {
 | 
			
		||||
    std::scoped_lock lk{lock};
 | 
			
		||||
 | 
			
		||||
    last_id++;
 | 
			
		||||
 | 
			
		||||
    producers[last_id] = std::move(binder);
 | 
			
		||||
    binders[last_id] = std::move(binder);
 | 
			
		||||
 | 
			
		||||
    return last_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) {
 | 
			
		||||
void HosBinderDriverServer::UnregisterBinder(s32 binder_id) {
 | 
			
		||||
    std::scoped_lock lk{lock};
 | 
			
		||||
 | 
			
		||||
    if (auto search = producers.find(id); search != producers.end()) {
 | 
			
		||||
        return search->second.get();
 | 
			
		||||
    binders.erase(binder_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<android::IBinder> HosBinderDriverServer::TryGetBinder(s32 id) const {
 | 
			
		||||
    std::scoped_lock lk{lock};
 | 
			
		||||
 | 
			
		||||
    if (auto search = binders.find(id); search != binders.end()) {
 | 
			
		||||
        return search->second;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/service/kernel_helpers.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/binder.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
@@ -19,19 +18,18 @@ namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
class HosBinderDriverServer final {
 | 
			
		||||
public:
 | 
			
		||||
    explicit HosBinderDriverServer(Core::System& system_);
 | 
			
		||||
    explicit HosBinderDriverServer();
 | 
			
		||||
    ~HosBinderDriverServer();
 | 
			
		||||
 | 
			
		||||
    u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder);
 | 
			
		||||
    s32 RegisterBinder(std::shared_ptr<android::IBinder>&& binder);
 | 
			
		||||
    void UnregisterBinder(s32 binder_id);
 | 
			
		||||
 | 
			
		||||
    android::IBinder* TryGetProducer(u64 id);
 | 
			
		||||
    std::shared_ptr<android::IBinder> TryGetBinder(s32 id) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KernelHelpers::ServiceContext service_context;
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers;
 | 
			
		||||
    std::mutex lock;
 | 
			
		||||
    u64 last_id{};
 | 
			
		||||
    std::unordered_map<s32, std::shared_ptr<android::IBinder>> binders;
 | 
			
		||||
    mutable std::mutex lock;
 | 
			
		||||
    s32 last_id{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 
 | 
			
		||||
@@ -1,335 +1,24 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <optional>
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/microprofile.h"
 | 
			
		||||
#include "common/scope_exit.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/core_timing.h"
 | 
			
		||||
#include "core/hle/kernel/k_readable_event.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/nvdrv.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hardware_composer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hos_binder_driver.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.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"
 | 
			
		||||
#include "video_core/gpu.h"
 | 
			
		||||
#include "video_core/host1x/host1x.h"
 | 
			
		||||
#include "video_core/host1x/syncpoint_manager.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/surface_flinger.h"
 | 
			
		||||
#include "core/hle/service/server_manager.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
 | 
			
		||||
 | 
			
		||||
void Nvnflinger::SplitVSync(std::stop_token stop_token) {
 | 
			
		||||
    system.RegisterHostThread();
 | 
			
		||||
    std::string name = "VSyncThread";
 | 
			
		||||
    MicroProfileOnThreadCreate(name.c_str());
 | 
			
		||||
 | 
			
		||||
    // Cleanup
 | 
			
		||||
    SCOPE_EXIT({ MicroProfileOnThreadExit(); });
 | 
			
		||||
 | 
			
		||||
    Common::SetCurrentThreadName(name.c_str());
 | 
			
		||||
    Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
 | 
			
		||||
 | 
			
		||||
    while (!stop_token.stop_requested()) {
 | 
			
		||||
        vsync_signal.Wait();
 | 
			
		||||
 | 
			
		||||
        const auto lock_guard = Lock();
 | 
			
		||||
 | 
			
		||||
        if (!is_abandoned) {
 | 
			
		||||
            Compose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
 | 
			
		||||
    : system(system_), service_context(system_, "nvnflinger"),
 | 
			
		||||
      hos_binder_driver_server(hos_binder_driver_server_) {
 | 
			
		||||
    displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system);
 | 
			
		||||
    displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system);
 | 
			
		||||
    displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system);
 | 
			
		||||
    displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system);
 | 
			
		||||
    displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system);
 | 
			
		||||
    guard = std::make_shared<std::mutex>();
 | 
			
		||||
 | 
			
		||||
    // Schedule the screen composition events
 | 
			
		||||
    multi_composition_event = Core::Timing::CreateEvent(
 | 
			
		||||
        "ScreenComposition",
 | 
			
		||||
        [this](s64 time,
 | 
			
		||||
               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
 | 
			
		||||
            vsync_signal.Set();
 | 
			
		||||
            return std::chrono::nanoseconds(GetNextTicks());
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    single_composition_event = Core::Timing::CreateEvent(
 | 
			
		||||
        "ScreenComposition",
 | 
			
		||||
        [this](s64 time,
 | 
			
		||||
               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
 | 
			
		||||
            const auto lock_guard = Lock();
 | 
			
		||||
            Compose();
 | 
			
		||||
 | 
			
		||||
            return std::chrono::nanoseconds(GetNextTicks());
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    if (system.IsMulticore()) {
 | 
			
		||||
        system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, multi_composition_event);
 | 
			
		||||
        vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
 | 
			
		||||
    } else {
 | 
			
		||||
        system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, single_composition_event);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Nvnflinger::~Nvnflinger() {
 | 
			
		||||
    if (system.IsMulticore()) {
 | 
			
		||||
        system.CoreTiming().UnscheduleEvent(multi_composition_event);
 | 
			
		||||
        vsync_thread.request_stop();
 | 
			
		||||
        vsync_signal.Set();
 | 
			
		||||
    } else {
 | 
			
		||||
        system.CoreTiming().UnscheduleEvent(single_composition_event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ShutdownLayers();
 | 
			
		||||
 | 
			
		||||
    if (nvdrv) {
 | 
			
		||||
        nvdrv->Close(disp_fd);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Nvnflinger::ShutdownLayers() {
 | 
			
		||||
    // Abandon consumers.
 | 
			
		||||
    {
 | 
			
		||||
        const auto lock_guard = Lock();
 | 
			
		||||
        for (auto& display : displays) {
 | 
			
		||||
            display.Abandon();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        is_abandoned = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Join the vsync thread, if it exists.
 | 
			
		||||
    vsync_thread = {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
 | 
			
		||||
    nvdrv = std::move(instance);
 | 
			
		||||
    disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_Nvnflinger, "Opening \"{}\" display", name);
 | 
			
		||||
 | 
			
		||||
    const auto itr =
 | 
			
		||||
        std::find_if(displays.begin(), displays.end(),
 | 
			
		||||
                     [&](const VI::Display& display) { return display.GetName() == name; });
 | 
			
		||||
 | 
			
		||||
    if (itr == displays.end()) {
 | 
			
		||||
        return std::nullopt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return itr->GetID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Nvnflinger::CloseDisplay(u64 display_id) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
    auto* const display = FindDisplay(display_id);
 | 
			
		||||
 | 
			
		||||
    if (display == nullptr) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    display->Reset();
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
    auto* const display = FindDisplay(display_id);
 | 
			
		||||
 | 
			
		||||
    if (display == nullptr) {
 | 
			
		||||
        return std::nullopt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const u64 layer_id = next_layer_id++;
 | 
			
		||||
    CreateLayerAtId(*display, layer_id, blending);
 | 
			
		||||
    return layer_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) {
 | 
			
		||||
    const auto buffer_id = next_buffer_queue_id++;
 | 
			
		||||
    display.CreateLayer(layer_id, buffer_id, nvdrv->container);
 | 
			
		||||
    display.FindLayer(layer_id)->SetBlending(blending);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Nvnflinger::OpenLayer(u64 layer_id) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
 | 
			
		||||
    for (auto& display : displays) {
 | 
			
		||||
        if (auto* layer = display.FindLayer(layer_id); layer) {
 | 
			
		||||
            return layer->Open();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Nvnflinger::CloseLayer(u64 layer_id) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
 | 
			
		||||
    for (auto& display : displays) {
 | 
			
		||||
        if (auto* layer = display.FindLayer(layer_id); layer) {
 | 
			
		||||
            return layer->Close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
 | 
			
		||||
    for (auto& display : displays) {
 | 
			
		||||
        if (auto* layer = display.FindLayer(layer_id); layer) {
 | 
			
		||||
            layer->SetVisibility(visible);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Nvnflinger::DestroyLayer(u64 layer_id) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
 | 
			
		||||
    for (auto& display : displays) {
 | 
			
		||||
        display.DestroyLayer(layer_id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
    const auto* const layer = FindLayer(display_id, layer_id);
 | 
			
		||||
 | 
			
		||||
    if (layer == nullptr) {
 | 
			
		||||
        return std::nullopt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return layer->GetBinderId();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
    auto* const display = FindDisplay(display_id);
 | 
			
		||||
 | 
			
		||||
    if (display == nullptr) {
 | 
			
		||||
        return VI::ResultNotFound;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out_vsync_event = display->GetVSyncEvent();
 | 
			
		||||
    return ResultSuccess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
 | 
			
		||||
    const auto itr =
 | 
			
		||||
        std::find_if(displays.begin(), displays.end(),
 | 
			
		||||
                     [&](const VI::Display& display) { return display.GetID() == display_id; });
 | 
			
		||||
 | 
			
		||||
    if (itr == displays.end()) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return &*itr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VI::Display* Nvnflinger::FindDisplay(u64 display_id) const {
 | 
			
		||||
    const auto itr =
 | 
			
		||||
        std::find_if(displays.begin(), displays.end(),
 | 
			
		||||
                     [&](const VI::Display& display) { return display.GetID() == display_id; });
 | 
			
		||||
 | 
			
		||||
    if (itr == displays.end()) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return &*itr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) {
 | 
			
		||||
    auto* const display = FindDisplay(display_id);
 | 
			
		||||
 | 
			
		||||
    if (display == nullptr) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return display->FindLayer(layer_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Nvnflinger::Compose() {
 | 
			
		||||
    for (auto& display : displays) {
 | 
			
		||||
        // Trigger vsync for this display at the end of drawing
 | 
			
		||||
        SCOPE_EXIT({ display.SignalVSyncEvent(); });
 | 
			
		||||
 | 
			
		||||
        // Don't do anything for displays without layers.
 | 
			
		||||
        if (!display.HasLayers()) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!system.IsPoweredOn()) {
 | 
			
		||||
            return; // We are likely shutting down
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
 | 
			
		||||
        ASSERT(nvdisp);
 | 
			
		||||
 | 
			
		||||
        swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
s64 Nvnflinger::GetNextTicks() const {
 | 
			
		||||
    const auto& settings = Settings::values;
 | 
			
		||||
    auto speed_scale = 1.f;
 | 
			
		||||
    if (settings.use_multi_core.GetValue()) {
 | 
			
		||||
        if (settings.use_speed_limit.GetValue()) {
 | 
			
		||||
            // Scales the speed based on speed_limit setting on MC. SC is handled by
 | 
			
		||||
            // SpeedLimiter::DoSpeedLimiting.
 | 
			
		||||
            speed_scale = 100.f / settings.speed_limit.GetValue();
 | 
			
		||||
        } else {
 | 
			
		||||
            // Run at unlocked framerate.
 | 
			
		||||
            speed_scale = 0.01f;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Adjust by speed limit determined during composition.
 | 
			
		||||
    speed_scale /= compose_speed_scale;
 | 
			
		||||
 | 
			
		||||
    if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
 | 
			
		||||
        // Run at intended presentation rate during video playback.
 | 
			
		||||
        speed_scale = 1.f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
 | 
			
		||||
    return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FbShareBufferManager& Nvnflinger::GetSystemBufferManager() {
 | 
			
		||||
    const auto lock_guard = Lock();
 | 
			
		||||
 | 
			
		||||
    if (!system_buffer_manager) {
 | 
			
		||||
        system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return *system_buffer_manager;
 | 
			
		||||
void LoopProcess(Core::System& system) {
 | 
			
		||||
    const auto binder_server = std::make_shared<HosBinderDriverServer>();
 | 
			
		||||
    const auto surface_flinger = std::make_shared<SurfaceFlinger>(system, *binder_server);
 | 
			
		||||
 | 
			
		||||
    auto server_manager = std::make_unique<ServerManager>(system);
 | 
			
		||||
    server_manager->RegisterNamedService(
 | 
			
		||||
        "dispdrv", std::make_shared<IHOSBinderDriver>(system, binder_server, surface_flinger));
 | 
			
		||||
    ServerManager::RunServer(std::move(server_manager));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 
 | 
			
		||||
@@ -3,170 +3,12 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
#include "core/hle/service/kernel_helpers.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hwc_layer.h"
 | 
			
		||||
 | 
			
		||||
namespace Common {
 | 
			
		||||
class Event;
 | 
			
		||||
} // namespace Common
 | 
			
		||||
 | 
			
		||||
namespace Core::Timing {
 | 
			
		||||
class CoreTiming;
 | 
			
		||||
struct EventType;
 | 
			
		||||
} // namespace Core::Timing
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
class KReadableEvent;
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvidia {
 | 
			
		||||
class Module;
 | 
			
		||||
} // namespace Service::Nvidia
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
class Display;
 | 
			
		||||
class Layer;
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
class BufferQueueCore;
 | 
			
		||||
class BufferQueueProducer;
 | 
			
		||||
} // namespace Service::android
 | 
			
		||||
namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
class FbShareBufferManager;
 | 
			
		||||
class HardwareComposer;
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
 | 
			
		||||
class Nvnflinger final {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
 | 
			
		||||
    ~Nvnflinger();
 | 
			
		||||
 | 
			
		||||
    void ShutdownLayers();
 | 
			
		||||
 | 
			
		||||
    /// Sets the NVDrv module instance to use to send buffers to the GPU.
 | 
			
		||||
    void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
 | 
			
		||||
 | 
			
		||||
    /// Opens the specified display and returns the ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// If an invalid display name is provided, then an empty optional is returned.
 | 
			
		||||
    [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name);
 | 
			
		||||
 | 
			
		||||
    /// Closes the specified display by its ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Returns false if an invalid display ID is provided.
 | 
			
		||||
    [[nodiscard]] bool CloseDisplay(u64 display_id);
 | 
			
		||||
 | 
			
		||||
    /// Creates a layer on the specified display and returns the layer ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// If an invalid display ID is specified, then an empty optional is returned.
 | 
			
		||||
    [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id,
 | 
			
		||||
                                                 LayerBlending blending = LayerBlending::None);
 | 
			
		||||
 | 
			
		||||
    /// Opens a layer on all displays for the given layer ID.
 | 
			
		||||
    bool OpenLayer(u64 layer_id);
 | 
			
		||||
 | 
			
		||||
    /// Closes a layer on all displays for the given layer ID.
 | 
			
		||||
    bool CloseLayer(u64 layer_id);
 | 
			
		||||
 | 
			
		||||
    /// Makes a layer visible on all displays for the given layer ID.
 | 
			
		||||
    void SetLayerVisibility(u64 layer_id, bool visible);
 | 
			
		||||
 | 
			
		||||
    /// Destroys the given layer ID.
 | 
			
		||||
    void DestroyLayer(u64 layer_id);
 | 
			
		||||
 | 
			
		||||
    /// Finds the buffer queue ID of the specified layer in the specified display.
 | 
			
		||||
    ///
 | 
			
		||||
    /// If an invalid display ID or layer ID is provided, then an empty optional is returned.
 | 
			
		||||
    [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id);
 | 
			
		||||
 | 
			
		||||
    /// Gets the vsync event for the specified display.
 | 
			
		||||
    ///
 | 
			
		||||
    /// If an invalid display ID is provided, then VI::ResultNotFound is returned.
 | 
			
		||||
    /// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned.
 | 
			
		||||
    [[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id);
 | 
			
		||||
 | 
			
		||||
    /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
 | 
			
		||||
    /// finished.
 | 
			
		||||
    void Compose();
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] s64 GetNextTicks() const;
 | 
			
		||||
 | 
			
		||||
    FbShareBufferManager& GetSystemBufferManager();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct Layer {
 | 
			
		||||
        std::unique_ptr<android::BufferQueueCore> core;
 | 
			
		||||
        std::unique_ptr<android::BufferQueueProducer> producer;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    friend class FbShareBufferManager;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
 | 
			
		||||
        return std::unique_lock{*guard};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Finds the display identified by the specified ID.
 | 
			
		||||
    [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
 | 
			
		||||
 | 
			
		||||
    /// Finds the display identified by the specified ID.
 | 
			
		||||
    [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
 | 
			
		||||
 | 
			
		||||
    /// Finds the layer identified by the specified ID in the desired display.
 | 
			
		||||
    [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
 | 
			
		||||
 | 
			
		||||
    /// Creates a layer with the specified layer ID in the desired display.
 | 
			
		||||
    void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending);
 | 
			
		||||
 | 
			
		||||
    void SplitVSync(std::stop_token stop_token);
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Nvidia::Module> nvdrv;
 | 
			
		||||
    s32 disp_fd;
 | 
			
		||||
 | 
			
		||||
    std::list<VI::Display> displays;
 | 
			
		||||
 | 
			
		||||
    /// Id to use for the next layer that is created, this counter is shared among all displays.
 | 
			
		||||
    u64 next_layer_id = 1;
 | 
			
		||||
    /// Id to use for the next buffer queue that is created, this counter is shared among all
 | 
			
		||||
    /// layers.
 | 
			
		||||
    u32 next_buffer_queue_id = 1;
 | 
			
		||||
 | 
			
		||||
    s32 swap_interval = 1;
 | 
			
		||||
    f32 compose_speed_scale = 1.0f;
 | 
			
		||||
 | 
			
		||||
    bool is_abandoned = false;
 | 
			
		||||
 | 
			
		||||
    /// Event that handles screen composition.
 | 
			
		||||
    std::shared_ptr<Core::Timing::EventType> multi_composition_event;
 | 
			
		||||
    std::shared_ptr<Core::Timing::EventType> single_composition_event;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<FbShareBufferManager> system_buffer_manager;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<std::mutex> guard;
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
 | 
			
		||||
    Common::Event vsync_signal;
 | 
			
		||||
 | 
			
		||||
    std::jthread vsync_thread;
 | 
			
		||||
 | 
			
		||||
    KernelHelpers::ServiceContext service_context;
 | 
			
		||||
 | 
			
		||||
    HosBinderDriverServer& hos_binder_driver_server;
 | 
			
		||||
};
 | 
			
		||||
void LoopProcess(Core::System& system);
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										124
									
								
								src/core/hle/service/nvnflinger/surface_flinger.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/core/hle/service/nvnflinger/surface_flinger.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/nvdrv_interface.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/display.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/surface_flinger.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
SurfaceFlinger::SurfaceFlinger(Core::System& system, HosBinderDriverServer& server)
 | 
			
		||||
    : m_system(system), m_server(server), m_context(m_system, "SurfaceFlinger") {
 | 
			
		||||
    nvdrv = m_system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
 | 
			
		||||
    disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SurfaceFlinger::~SurfaceFlinger() {
 | 
			
		||||
    nvdrv->Close(disp_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::AddDisplay(u64 display_id) {
 | 
			
		||||
    m_displays.emplace_back(display_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::RemoveDisplay(u64 display_id) {
 | 
			
		||||
    std::erase_if(m_displays, [&](auto& display) { return display.id == display_id; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
 | 
			
		||||
                                    u64 display_id) {
 | 
			
		||||
    auto* const display = this->FindDisplay(display_id);
 | 
			
		||||
    if (!display || !display->HasLayers()) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out_swap_interval =
 | 
			
		||||
        m_composer.ComposeLocked(out_compose_speed_scale, *display,
 | 
			
		||||
                                 *nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
 | 
			
		||||
    auto* const display = this->FindDisplay(display_id);
 | 
			
		||||
    auto binder = std::static_pointer_cast<android::BufferQueueConsumer>(
 | 
			
		||||
        m_server.TryGetBinder(consumer_binder_id));
 | 
			
		||||
 | 
			
		||||
    if (!display || !binder) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder));
 | 
			
		||||
    buffer_item_consumer->Connect(false);
 | 
			
		||||
 | 
			
		||||
    display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) {
 | 
			
		||||
    auto* const display = this->FindDisplay(display_id);
 | 
			
		||||
    if (!display) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_composer.RemoveLayerLocked(*display, consumer_binder_id);
 | 
			
		||||
    std::erase_if(display->stack.layers,
 | 
			
		||||
                  [&](auto& layer) { return layer.consumer_id == consumer_binder_id; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) {
 | 
			
		||||
    if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
 | 
			
		||||
        layer->visible = visible;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) {
 | 
			
		||||
    if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
 | 
			
		||||
        layer->blending = blending;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Display* SurfaceFlinger::FindDisplay(u64 display_id) {
 | 
			
		||||
    for (auto& display : m_displays) {
 | 
			
		||||
        if (display.id == display_id) {
 | 
			
		||||
            return &display;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
 | 
			
		||||
    for (auto& display : m_displays) {
 | 
			
		||||
        if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) {
 | 
			
		||||
            return layer;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id) {
 | 
			
		||||
    auto& nvmap = nvdrv->GetContainer().GetNvMapFile();
 | 
			
		||||
    auto core = std::make_shared<android::BufferQueueCore>();
 | 
			
		||||
    auto producer = std::make_shared<android::BufferQueueProducer>(m_context, core, nvmap);
 | 
			
		||||
    auto consumer = std::make_shared<android::BufferQueueConsumer>(core);
 | 
			
		||||
 | 
			
		||||
    *out_consumer_binder_id = m_server.RegisterBinder(std::move(consumer));
 | 
			
		||||
    *out_producer_binder_id = m_server.RegisterBinder(std::move(producer));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SurfaceFlinger::DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id) {
 | 
			
		||||
    m_server.UnregisterBinder(producer_binder_id);
 | 
			
		||||
    m_server.UnregisterBinder(consumer_binder_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
							
								
								
									
										65
									
								
								src/core/hle/service/nvnflinger/surface_flinger.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/core/hle/service/nvnflinger/surface_flinger.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/service/kernel_helpers.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hardware_composer.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvidia {
 | 
			
		||||
class Module;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: ISurfaceComposer
 | 
			
		||||
// TODO: ISurfaceComposerClient
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
 | 
			
		||||
struct Display;
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
enum class LayerBlending : u32;
 | 
			
		||||
struct Layer;
 | 
			
		||||
 | 
			
		||||
class SurfaceFlinger {
 | 
			
		||||
public:
 | 
			
		||||
    explicit SurfaceFlinger(Core::System& system, HosBinderDriverServer& server);
 | 
			
		||||
    ~SurfaceFlinger();
 | 
			
		||||
 | 
			
		||||
    void AddDisplay(u64 display_id);
 | 
			
		||||
    void RemoveDisplay(u64 display_id);
 | 
			
		||||
    bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
 | 
			
		||||
 | 
			
		||||
    void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id);
 | 
			
		||||
    void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id);
 | 
			
		||||
 | 
			
		||||
    void SetLayerVisibility(s32 consumer_binder_id, bool visible);
 | 
			
		||||
    void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Display* FindDisplay(u64 display_id);
 | 
			
		||||
    Layer* FindLayer(s32 consumer_binder_id);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // TODO: these don't belong here
 | 
			
		||||
    void CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id);
 | 
			
		||||
    void DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Core::System& m_system;
 | 
			
		||||
    HosBinderDriverServer& m_server;
 | 
			
		||||
    KernelHelpers::ServiceContext m_context;
 | 
			
		||||
 | 
			
		||||
    std::vector<Display> m_displays;
 | 
			
		||||
    std::shared_ptr<Nvidia::Module> nvdrv;
 | 
			
		||||
    s32 disp_fd;
 | 
			
		||||
    HardwareComposer m_composer;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
@@ -7,68 +7,10 @@
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/ipc.h"
 | 
			
		||||
#include "core/hle/kernel/k_process.h"
 | 
			
		||||
#include "core/hle/kernel/k_server_port.h"
 | 
			
		||||
#include "core/hle/kernel/kernel.h"
 | 
			
		||||
#include "core/hle/service/acc/acc.h"
 | 
			
		||||
#include "core/hle/service/am/am.h"
 | 
			
		||||
#include "core/hle/service/aoc/aoc_u.h"
 | 
			
		||||
#include "core/hle/service/apm/apm.h"
 | 
			
		||||
#include "core/hle/service/audio/audio.h"
 | 
			
		||||
#include "core/hle/service/bcat/bcat.h"
 | 
			
		||||
#include "core/hle/service/bpc/bpc.h"
 | 
			
		||||
#include "core/hle/service/btdrv/btdrv.h"
 | 
			
		||||
#include "core/hle/service/btm/btm.h"
 | 
			
		||||
#include "core/hle/service/caps/caps.h"
 | 
			
		||||
#include "core/hle/service/erpt/erpt.h"
 | 
			
		||||
#include "core/hle/service/es/es.h"
 | 
			
		||||
#include "core/hle/service/eupld/eupld.h"
 | 
			
		||||
#include "core/hle/service/fatal/fatal.h"
 | 
			
		||||
#include "core/hle/service/fgm/fgm.h"
 | 
			
		||||
#include "core/hle/service/filesystem/filesystem.h"
 | 
			
		||||
#include "core/hle/service/friend/friend.h"
 | 
			
		||||
#include "core/hle/service/glue/glue.h"
 | 
			
		||||
#include "core/hle/service/grc/grc.h"
 | 
			
		||||
#include "core/hle/service/hid/hid.h"
 | 
			
		||||
#include "core/hle/service/ipc_helpers.h"
 | 
			
		||||
#include "core/hle/service/jit/jit.h"
 | 
			
		||||
#include "core/hle/service/lbl/lbl.h"
 | 
			
		||||
#include "core/hle/service/ldn/ldn.h"
 | 
			
		||||
#include "core/hle/service/ldr/ldr.h"
 | 
			
		||||
#include "core/hle/service/lm/lm.h"
 | 
			
		||||
#include "core/hle/service/mig/mig.h"
 | 
			
		||||
#include "core/hle/service/mii/mii.h"
 | 
			
		||||
#include "core/hle/service/mm/mm_u.h"
 | 
			
		||||
#include "core/hle/service/mnpp/mnpp_app.h"
 | 
			
		||||
#include "core/hle/service/ncm/ncm.h"
 | 
			
		||||
#include "core/hle/service/nfc/nfc.h"
 | 
			
		||||
#include "core/hle/service/nfp/nfp.h"
 | 
			
		||||
#include "core/hle/service/ngc/ngc.h"
 | 
			
		||||
#include "core/hle/service/nifm/nifm.h"
 | 
			
		||||
#include "core/hle/service/nim/nim.h"
 | 
			
		||||
#include "core/hle/service/npns/npns.h"
 | 
			
		||||
#include "core/hle/service/ns/ns.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/nvdrv.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
 | 
			
		||||
#include "core/hle/service/olsc/olsc.h"
 | 
			
		||||
#include "core/hle/service/omm/omm.h"
 | 
			
		||||
#include "core/hle/service/pcie/pcie.h"
 | 
			
		||||
#include "core/hle/service/pctl/pctl_module.h"
 | 
			
		||||
#include "core/hle/service/pcv/pcv.h"
 | 
			
		||||
#include "core/hle/service/pm/pm.h"
 | 
			
		||||
#include "core/hle/service/prepo/prepo.h"
 | 
			
		||||
#include "core/hle/service/psc/psc.h"
 | 
			
		||||
#include "core/hle/service/ptm/ptm.h"
 | 
			
		||||
#include "core/hle/service/ro/ro.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
#include "core/hle/service/set/settings.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "core/hle/service/sockets/sockets.h"
 | 
			
		||||
#include "core/hle/service/spl/spl_module.h"
 | 
			
		||||
#include "core/hle/service/ssl/ssl.h"
 | 
			
		||||
#include "core/hle/service/usb/usb.h"
 | 
			
		||||
#include "core/hle/service/vi/vi.h"
 | 
			
		||||
#include "core/reporter.h"
 | 
			
		||||
 | 
			
		||||
namespace Service {
 | 
			
		||||
@@ -209,82 +151,4 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Initialize Services
 | 
			
		||||
Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
 | 
			
		||||
    : hos_binder_driver_server{std::make_unique<Nvnflinger::HosBinderDriverServer>(system)},
 | 
			
		||||
      nv_flinger{std::make_unique<Nvnflinger::Nvnflinger>(system, *hos_binder_driver_server)} {
 | 
			
		||||
 | 
			
		||||
    auto& kernel = system.Kernel();
 | 
			
		||||
 | 
			
		||||
    // Nvnflinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
 | 
			
		||||
    // here and pass it into the respective InstallInterfaces functions.
 | 
			
		||||
    system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
 | 
			
		||||
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    kernel.RunOnHostCoreProcess("audio",      [&] { Audio::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("FS",         [&] { FileSystem::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("jit",        [&] { JIT::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("ldn",        [&] { LDN::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("Loader",     [&] { LDR::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(*nv_flinger, system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("bsdsocket",  [&] { Sockets::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("vi",         [&] { VI::LoopProcess(system, *nv_flinger, *hos_binder_driver_server); }).detach();
 | 
			
		||||
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("sm",         [&] { SM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("account",    [&] { Account::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("am",         [&] { AM::LoopProcess(*nv_flinger, system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("aoc",        [&] { AOC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("apm",        [&] { APM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("bcat",       [&] { BCAT::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("bpc",        [&] { BPC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("btdrv",      [&] { BtDrv::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("btm",        [&] { BTM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("capsrv",     [&] { Capture::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("erpt",       [&] { ERPT::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("es",         [&] { ES::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("eupld",      [&] { EUPLD::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("fatal",      [&] { Fatal::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("fgm",        [&] { FGM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("friends",    [&] { Friend::LoopProcess(system); });
 | 
			
		||||
    // glue depends on settings and psc, so they must come first
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("settings",   [&] { Set::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("psc",        [&] { PSC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("glue",       [&] { Glue::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("grc",        [&] { GRC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("hid",        [&] { HID::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("lbl",        [&] { LBL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mig",        [&] { Migration::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mii",        [&] { Mii::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mm",         [&] { MM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mnpp",       [&] { MNPP::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("NCM",        [&] { NCM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nfc",        [&] { NFC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nfp",        [&] { NFP::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ngc",        [&] { NGC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nifm",       [&] { NIFM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nim",        [&] { NIM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("npns",       [&] { NPNS::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ns",         [&] { NS::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("olsc",       [&] { OLSC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("omm",        [&] { OMM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("pcie",       [&] { PCIe::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("pctl",       [&] { PCTL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("pcv",        [&] { PCV::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("prepo",      [&] { PlayReport::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ptm",        [&] { PTM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ro",         [&] { RO::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("spl",        [&] { SPL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ssl",        [&] { SSL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("usb",        [&] { USB::LoopProcess(system); });
 | 
			
		||||
    // clang-format on
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Services::~Services() = default;
 | 
			
		||||
 | 
			
		||||
void Services::KillNVNFlinger() {
 | 
			
		||||
    nv_flinger->ShutdownLayers();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service
 | 
			
		||||
 
 | 
			
		||||
@@ -28,11 +28,6 @@ namespace FileSystem {
 | 
			
		||||
class FileSystemController;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Nvnflinger {
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
} // namespace Nvnflinger
 | 
			
		||||
 | 
			
		||||
namespace SM {
 | 
			
		||||
class ServiceManager;
 | 
			
		||||
}
 | 
			
		||||
@@ -236,20 +231,4 @@ private:
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The purpose of this class is to own any objects that need to be shared across the other service
 | 
			
		||||
 * implementations. Will be torn down when the global system instance is shutdown.
 | 
			
		||||
 */
 | 
			
		||||
class Services final {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
 | 
			
		||||
    ~Services();
 | 
			
		||||
 | 
			
		||||
    void KillNVNFlinger();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<Nvnflinger::HosBinderDriverServer> hos_binder_driver_server;
 | 
			
		||||
    std::unique_ptr<Nvnflinger::Nvnflinger> nv_flinger;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										136
									
								
								src/core/hle/service/services.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/core/hle/service/services.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/services.h"
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/acc/acc.h"
 | 
			
		||||
#include "core/hle/service/am/am.h"
 | 
			
		||||
#include "core/hle/service/aoc/aoc_u.h"
 | 
			
		||||
#include "core/hle/service/apm/apm.h"
 | 
			
		||||
#include "core/hle/service/audio/audio.h"
 | 
			
		||||
#include "core/hle/service/bcat/bcat.h"
 | 
			
		||||
#include "core/hle/service/bpc/bpc.h"
 | 
			
		||||
#include "core/hle/service/btdrv/btdrv.h"
 | 
			
		||||
#include "core/hle/service/btm/btm.h"
 | 
			
		||||
#include "core/hle/service/caps/caps.h"
 | 
			
		||||
#include "core/hle/service/erpt/erpt.h"
 | 
			
		||||
#include "core/hle/service/es/es.h"
 | 
			
		||||
#include "core/hle/service/eupld/eupld.h"
 | 
			
		||||
#include "core/hle/service/fatal/fatal.h"
 | 
			
		||||
#include "core/hle/service/fgm/fgm.h"
 | 
			
		||||
#include "core/hle/service/filesystem/filesystem.h"
 | 
			
		||||
#include "core/hle/service/friend/friend.h"
 | 
			
		||||
#include "core/hle/service/glue/glue.h"
 | 
			
		||||
#include "core/hle/service/grc/grc.h"
 | 
			
		||||
#include "core/hle/service/hid/hid.h"
 | 
			
		||||
#include "core/hle/service/ipc_helpers.h"
 | 
			
		||||
#include "core/hle/service/jit/jit.h"
 | 
			
		||||
#include "core/hle/service/lbl/lbl.h"
 | 
			
		||||
#include "core/hle/service/ldn/ldn.h"
 | 
			
		||||
#include "core/hle/service/ldr/ldr.h"
 | 
			
		||||
#include "core/hle/service/lm/lm.h"
 | 
			
		||||
#include "core/hle/service/mig/mig.h"
 | 
			
		||||
#include "core/hle/service/mii/mii.h"
 | 
			
		||||
#include "core/hle/service/mm/mm_u.h"
 | 
			
		||||
#include "core/hle/service/mnpp/mnpp_app.h"
 | 
			
		||||
#include "core/hle/service/ncm/ncm.h"
 | 
			
		||||
#include "core/hle/service/nfc/nfc.h"
 | 
			
		||||
#include "core/hle/service/nfp/nfp.h"
 | 
			
		||||
#include "core/hle/service/ngc/ngc.h"
 | 
			
		||||
#include "core/hle/service/nifm/nifm.h"
 | 
			
		||||
#include "core/hle/service/nim/nim.h"
 | 
			
		||||
#include "core/hle/service/npns/npns.h"
 | 
			
		||||
#include "core/hle/service/ns/ns.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/nvdrv.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
 | 
			
		||||
#include "core/hle/service/olsc/olsc.h"
 | 
			
		||||
#include "core/hle/service/omm/omm.h"
 | 
			
		||||
#include "core/hle/service/pcie/pcie.h"
 | 
			
		||||
#include "core/hle/service/pctl/pctl_module.h"
 | 
			
		||||
#include "core/hle/service/pcv/pcv.h"
 | 
			
		||||
#include "core/hle/service/pm/pm.h"
 | 
			
		||||
#include "core/hle/service/prepo/prepo.h"
 | 
			
		||||
#include "core/hle/service/psc/psc.h"
 | 
			
		||||
#include "core/hle/service/ptm/ptm.h"
 | 
			
		||||
#include "core/hle/service/ro/ro.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
#include "core/hle/service/set/settings.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "core/hle/service/sockets/sockets.h"
 | 
			
		||||
#include "core/hle/service/spl/spl_module.h"
 | 
			
		||||
#include "core/hle/service/ssl/ssl.h"
 | 
			
		||||
#include "core/hle/service/usb/usb.h"
 | 
			
		||||
#include "core/hle/service/vi/vi.h"
 | 
			
		||||
 | 
			
		||||
namespace Service {
 | 
			
		||||
 | 
			
		||||
Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
 | 
			
		||||
                   std::stop_token token) {
 | 
			
		||||
    auto& kernel = system.Kernel();
 | 
			
		||||
 | 
			
		||||
    system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
 | 
			
		||||
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    kernel.RunOnHostCoreProcess("audio",      [&] { Audio::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("FS",         [&] { FileSystem::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("jit",        [&] { JIT::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("ldn",        [&] { LDN::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("Loader",     [&] { LDR::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("bsdsocket",  [&] { Sockets::LoopProcess(system); }).detach();
 | 
			
		||||
    kernel.RunOnHostCoreProcess("vi",         [&, token] { VI::LoopProcess(system, token); }).detach();
 | 
			
		||||
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("sm",         [&] { SM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("account",    [&] { Account::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("am",         [&] { AM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("aoc",        [&] { AOC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("apm",        [&] { APM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("bcat",       [&] { BCAT::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("bpc",        [&] { BPC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("btdrv",      [&] { BtDrv::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("btm",        [&] { BTM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("capsrv",     [&] { Capture::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("erpt",       [&] { ERPT::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("es",         [&] { ES::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("eupld",      [&] { EUPLD::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("fatal",      [&] { Fatal::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("fgm",        [&] { FGM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("friends",    [&] { Friend::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("settings",   [&] { Set::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("psc",        [&] { PSC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("glue",       [&] { Glue::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("grc",        [&] { GRC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("hid",        [&] { HID::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("lbl",        [&] { LBL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mig",        [&] { Migration::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mii",        [&] { Mii::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mm",         [&] { MM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("mnpp",       [&] { MNPP::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nvnflinger", [&] { Nvnflinger::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("NCM",        [&] { NCM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nfc",        [&] { NFC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nfp",        [&] { NFP::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ngc",        [&] { NGC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nifm",       [&] { NIFM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("nim",        [&] { NIM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("npns",       [&] { NPNS::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ns",         [&] { NS::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("olsc",       [&] { OLSC::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("omm",        [&] { OMM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("pcie",       [&] { PCIe::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("pctl",       [&] { PCTL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("pcv",        [&] { PCV::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("prepo",      [&] { PlayReport::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ptm",        [&] { PTM::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ro",         [&] { RO::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("spl",        [&] { SPL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("ssl",        [&] { SSL::LoopProcess(system); });
 | 
			
		||||
    kernel.RunOnGuestCoreProcess("usb",        [&] { USB::LoopProcess(system); });
 | 
			
		||||
    // clang-format on
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Services::~Services() = default;
 | 
			
		||||
 | 
			
		||||
} // namespace Service
 | 
			
		||||
							
								
								
									
										22
									
								
								src/core/hle/service/services.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/core/hle/service/services.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
 | 
			
		||||
namespace Service {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The purpose of this class is to own any objects that need to be shared across the other service
 | 
			
		||||
 * implementations. Will be torn down when the global system instance is shutdown.
 | 
			
		||||
 */
 | 
			
		||||
class Services final {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
 | 
			
		||||
                      std::stop_token token);
 | 
			
		||||
    ~Services();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service
 | 
			
		||||
@@ -2,22 +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/nvnflinger/hos_binder_driver.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/hos_binder_driver.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_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
 | 
			
		||||
    : ServiceFramework{system_, "IApplicationDisplayService"}, m_nvnflinger{nvnflinger},
 | 
			
		||||
      m_hos_binder_driver_server{hos_binder_driver_server} {
 | 
			
		||||
 | 
			
		||||
IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
 | 
			
		||||
                                                       std::shared_ptr<Container> container)
 | 
			
		||||
    : ServiceFramework{system_, "IApplicationDisplayService"},
 | 
			
		||||
      m_container{std::move(container)}, m_context{system, "IApplicationDisplayService"} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"},
 | 
			
		||||
@@ -48,38 +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_nvnflinger.DestroyLayer(layer_id);
 | 
			
		||||
        m_container->DestroyStrayLayer(layer_id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IApplicationDisplayService::GetRelayService(
 | 
			
		||||
    Out<SharedPointer<IHOSBinderDriver>> out_relay_service) {
 | 
			
		||||
    Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) {
 | 
			
		||||
    LOG_WARNING(Service_VI, "(STUBBED) called");
 | 
			
		||||
    *out_relay_service = std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server);
 | 
			
		||||
    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_nvnflinger);
 | 
			
		||||
    *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_nvnflinger);
 | 
			
		||||
    *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_container);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IApplicationDisplayService::GetIndirectDisplayTransactionService(
 | 
			
		||||
    Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service) {
 | 
			
		||||
    Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service) {
 | 
			
		||||
    LOG_WARNING(Service_VI, "(STUBBED) called");
 | 
			
		||||
    *out_indirect_display_transaction_service =
 | 
			
		||||
        std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
    R_RETURN(m_container->GetBinderDriver(out_indirect_display_transaction_service));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) {
 | 
			
		||||
@@ -89,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_nvnflinger.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) {
 | 
			
		||||
@@ -106,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_nvnflinger.CloseDisplay(display_id));
 | 
			
		||||
    R_THROW(ResultUnknown);
 | 
			
		||||
    R_RETURN(m_container->CloseDisplay(display_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) {
 | 
			
		||||
@@ -168,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_nvnflinger.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_nvnflinger.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_nvnflinger.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(),
 | 
			
		||||
@@ -199,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_nvnflinger.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(
 | 
			
		||||
@@ -212,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_nvnflinger.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_nvnflinger.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();
 | 
			
		||||
@@ -240,25 +221,27 @@ Result IApplicationDisplayService::CreateStrayLayer(
 | 
			
		||||
 | 
			
		||||
Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) {
 | 
			
		||||
    LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
 | 
			
		||||
    m_nvnflinger.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_nvnflinger.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();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 | 
			
		||||
@@ -9,26 +14,33 @@ namespace Kernel {
 | 
			
		||||
class KReadableEvent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class IHOSBinderDriver;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
class IHOSBinderDriver;
 | 
			
		||||
class Container;
 | 
			
		||||
class IManagerDisplayService;
 | 
			
		||||
class ISystemDisplayService;
 | 
			
		||||
 | 
			
		||||
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
 | 
			
		||||
public:
 | 
			
		||||
    IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
                               Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
 | 
			
		||||
    IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container);
 | 
			
		||||
    ~IApplicationDisplayService() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Result GetRelayService(Out<SharedPointer<IHOSBinderDriver>> out_relay_service);
 | 
			
		||||
    std::shared_ptr<Container> GetContainer() const {
 | 
			
		||||
        return m_container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service);
 | 
			
		||||
    Result GetSystemDisplayService(
 | 
			
		||||
        Out<SharedPointer<ISystemDisplayService>> out_system_display_service);
 | 
			
		||||
    Result GetManagerDisplayService(
 | 
			
		||||
        Out<SharedPointer<IManagerDisplayService>> out_manager_display_service);
 | 
			
		||||
    Result GetIndirectDisplayTransactionService(
 | 
			
		||||
        Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service);
 | 
			
		||||
        Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service);
 | 
			
		||||
    Result OpenDisplay(Out<u64> out_display_id, DisplayName display_name);
 | 
			
		||||
    Result OpenDefaultDisplay(Out<u64> out_display_id);
 | 
			
		||||
    Result CloseDisplay(u64 display_id);
 | 
			
		||||
@@ -56,9 +68,13 @@ private:
 | 
			
		||||
                                                   s64 width, s64 height);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
 | 
			
		||||
    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};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
 | 
			
		||||
    : ServiceFramework{system_, "vi:u"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
 | 
			
		||||
                                                                       hos_binder_driver_server} {
 | 
			
		||||
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_nvnflinger,
 | 
			
		||||
                                          m_hos_binder_driver_server, Permission::User, policy));
 | 
			
		||||
    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
 | 
			
		||||
                                          Permission::User, policy));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -10,20 +10,15 @@ namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
class Container;
 | 
			
		||||
class IApplicationDisplayService;
 | 
			
		||||
enum class Policy : u32;
 | 
			
		||||
 | 
			
		||||
class IApplicationRootService final : public ServiceFramework<IApplicationRootService> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IApplicationRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
                                     Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
 | 
			
		||||
    explicit IApplicationRootService(Core::System& system_, std::shared_ptr<Container> container);
 | 
			
		||||
    ~IApplicationRootService() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -32,8 +27,7 @@ private:
 | 
			
		||||
        Policy policy);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
 | 
			
		||||
    const std::shared_ptr<Container> m_container;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										114
									
								
								src/core/hle/service/vi/conductor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/core/hle/service/vi/conductor.cpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										57
									
								
								src/core/hle/service/vi/conductor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/core/hle/service/vi/conductor.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										228
									
								
								src/core/hle/service/vi/container.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/core/hle/service/vi/container.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
			
		||||
// 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());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										92
									
								
								src/core/hle/service/vi/container.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/core/hle/service/vi/container.h
									
									
									
									
									
										Normal 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:
 | 
			
		||||
    bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::mutex m_lock{};
 | 
			
		||||
    DisplayList m_displays{};
 | 
			
		||||
    LayerList m_layers{};
 | 
			
		||||
    std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_driver{};
 | 
			
		||||
    std::shared_ptr<Nvnflinger::SurfaceFlinger> m_surface_flinger{};
 | 
			
		||||
    std::optional<SharedBufferManager> m_shared_buffer_manager{};
 | 
			
		||||
    std::optional<Conductor> m_conductor{};
 | 
			
		||||
    bool m_is_shut_down{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
							
								
								
									
										44
									
								
								src/core/hle/service/vi/display.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/core/hle/service/vi/display.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -1,143 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
class KEvent;
 | 
			
		||||
class KReadableEvent;
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
class BufferQueueProducer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::KernelHelpers {
 | 
			
		||||
class ServiceContext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class HardwareComposer;
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvidia::NvCore {
 | 
			
		||||
class Container;
 | 
			
		||||
class NvMap;
 | 
			
		||||
} // namespace Service::Nvidia::NvCore
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
class Layer;
 | 
			
		||||
 | 
			
		||||
/// Represents a single display type
 | 
			
		||||
class Display {
 | 
			
		||||
public:
 | 
			
		||||
    YUZU_NON_COPYABLE(Display);
 | 
			
		||||
    YUZU_NON_MOVEABLE(Display);
 | 
			
		||||
 | 
			
		||||
    /// Constructs a display with a given unique ID and name.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param id The unique ID for this display.
 | 
			
		||||
    /// @param hos_binder_driver_server_ Nvnflinger HOSBinderDriver server instance.
 | 
			
		||||
    /// @param service_context_ The ServiceContext for the owning service.
 | 
			
		||||
    /// @param name_ The name for this display.
 | 
			
		||||
    /// @param system_ The global system instance.
 | 
			
		||||
    ///
 | 
			
		||||
    Display(u64 id, std::string name_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
 | 
			
		||||
            KernelHelpers::ServiceContext& service_context_, Core::System& system_);
 | 
			
		||||
    ~Display();
 | 
			
		||||
 | 
			
		||||
    /// Gets the unique ID assigned to this display.
 | 
			
		||||
    u64 GetID() const {
 | 
			
		||||
        return display_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Gets the name of this display
 | 
			
		||||
    const std::string& GetName() const {
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Whether or not this display has any layers added to it.
 | 
			
		||||
    bool HasLayers() const {
 | 
			
		||||
        return GetNumLayers() > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Gets a layer for this display based off an index.
 | 
			
		||||
    Layer& GetLayer(std::size_t index);
 | 
			
		||||
 | 
			
		||||
    std::size_t GetNumLayers() const;
 | 
			
		||||
 | 
			
		||||
    /// Gets the internal vsync event.
 | 
			
		||||
    Kernel::KReadableEvent* GetVSyncEvent();
 | 
			
		||||
 | 
			
		||||
    /// Signals the internal vsync event.
 | 
			
		||||
    void SignalVSyncEvent();
 | 
			
		||||
 | 
			
		||||
    /// Creates and adds a layer to this display with the given ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param layer_id The ID to assign to the created layer.
 | 
			
		||||
    /// @param binder_id The ID assigned to the buffer queue.
 | 
			
		||||
    ///
 | 
			
		||||
    void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core);
 | 
			
		||||
 | 
			
		||||
    /// Removes a layer from this display with the given ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param layer_id The ID assigned to the layer to destroy.
 | 
			
		||||
    ///
 | 
			
		||||
    void DestroyLayer(u64 layer_id);
 | 
			
		||||
 | 
			
		||||
    /// Resets the display for a new connection.
 | 
			
		||||
    void Reset() {
 | 
			
		||||
        layers.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Abandon();
 | 
			
		||||
 | 
			
		||||
    /// Attempts to find a layer with the given ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param layer_id The layer ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @returns If found, the Layer instance with the given ID.
 | 
			
		||||
    ///          If not found, then nullptr is returned.
 | 
			
		||||
    ///
 | 
			
		||||
    Layer* FindLayer(u64 layer_id);
 | 
			
		||||
 | 
			
		||||
    /// Attempts to find a layer with the given ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param layer_id The layer ID.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @returns If found, the Layer instance with the given ID.
 | 
			
		||||
    ///          If not found, then nullptr is returned.
 | 
			
		||||
    ///
 | 
			
		||||
    const Layer* FindLayer(u64 layer_id) const;
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::HardwareComposer& GetComposer() const {
 | 
			
		||||
        return *hardware_composer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    u64 display_id;
 | 
			
		||||
    std::string name;
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
 | 
			
		||||
    KernelHelpers::ServiceContext& service_context;
 | 
			
		||||
 | 
			
		||||
    std::vector<std::unique_ptr<Layer>> layers;
 | 
			
		||||
    std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer;
 | 
			
		||||
    Kernel::KEvent* vsync_event{};
 | 
			
		||||
    bool is_abandoned{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
							
								
								
									
										83
									
								
								src/core/hle/service/vi/display_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/core/hle/service/vi/display_list.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										79
									
								
								src/core/hle/service/vi/layer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/core/hle/service/vi/layer.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -1,118 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::android {
 | 
			
		||||
class BufferItemConsumer;
 | 
			
		||||
class BufferQueueCore;
 | 
			
		||||
class BufferQueueProducer;
 | 
			
		||||
} // namespace Service::android
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
enum class LayerBlending : u32;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
/// Represents a single display layer.
 | 
			
		||||
class Layer {
 | 
			
		||||
public:
 | 
			
		||||
    /// Constructs a layer with a given ID and buffer queue.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param layer_id_ The ID to assign to this layer.
 | 
			
		||||
    /// @param binder_id_ The binder ID to assign to this layer.
 | 
			
		||||
    /// @param binder_ The buffer producer queue for this layer to use.
 | 
			
		||||
    ///
 | 
			
		||||
    Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
 | 
			
		||||
          android::BufferQueueProducer& binder_,
 | 
			
		||||
          std::shared_ptr<android::BufferItemConsumer>&& consumer_);
 | 
			
		||||
    ~Layer();
 | 
			
		||||
 | 
			
		||||
    Layer(const Layer&) = delete;
 | 
			
		||||
    Layer& operator=(const Layer&) = delete;
 | 
			
		||||
 | 
			
		||||
    Layer(Layer&&) = default;
 | 
			
		||||
    Layer& operator=(Layer&&) = delete;
 | 
			
		||||
 | 
			
		||||
    /// Gets the ID for this layer.
 | 
			
		||||
    u64 GetLayerId() const {
 | 
			
		||||
        return layer_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Gets the binder ID for this layer.
 | 
			
		||||
    u32 GetBinderId() const {
 | 
			
		||||
        return binder_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Gets a reference to the buffer queue this layer is using.
 | 
			
		||||
    android::BufferQueueProducer& GetBufferQueue() {
 | 
			
		||||
        return binder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Gets a const reference to the buffer queue this layer is using.
 | 
			
		||||
    const android::BufferQueueProducer& GetBufferQueue() const {
 | 
			
		||||
        return binder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    android::BufferItemConsumer& GetConsumer() {
 | 
			
		||||
        return *consumer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const android::BufferItemConsumer& GetConsumer() const {
 | 
			
		||||
        return *consumer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    android::BufferQueueCore& Core() {
 | 
			
		||||
        return core;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const android::BufferQueueCore& Core() const {
 | 
			
		||||
        return core;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsVisible() const {
 | 
			
		||||
        return visible;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SetVisibility(bool v) {
 | 
			
		||||
        visible = v;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsOpen() const {
 | 
			
		||||
        return open;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Close() {
 | 
			
		||||
        return std::exchange(open, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Open() {
 | 
			
		||||
        return !std::exchange(open, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::LayerBlending GetBlending() {
 | 
			
		||||
        return blending;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SetBlending(Nvnflinger::LayerBlending b) {
 | 
			
		||||
        blending = b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const u64 layer_id;
 | 
			
		||||
    const u32 binder_id;
 | 
			
		||||
    android::BufferQueueCore& core;
 | 
			
		||||
    android::BufferQueueProducer& binder;
 | 
			
		||||
    std::shared_ptr<android::BufferItemConsumer> consumer;
 | 
			
		||||
    Service::Nvnflinger::LayerBlending blending;
 | 
			
		||||
    bool open;
 | 
			
		||||
    bool visible;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
							
								
								
									
										69
									
								
								src/core/hle/service/vi/layer_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/core/hle/service/vi/layer_list.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -2,22 +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_,
 | 
			
		||||
                                               Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "IManagerDisplayService"}, m_nvnflinger{nvnflinger} {
 | 
			
		||||
                                               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"},
 | 
			
		||||
@@ -102,19 +101,30 @@ IManagerDisplayService::IManagerDisplayService(Core::System& system_,
 | 
			
		||||
 | 
			
		||||
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_nvnflinger.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) {
 | 
			
		||||
@@ -123,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
 | 
			
		||||
 
 | 
			
		||||
@@ -4,21 +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_, Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
    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:
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    const std::shared_ptr<Container> m_container;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#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"
 | 
			
		||||
@@ -10,11 +12,9 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
IManagerRootService::IManagerRootService(
 | 
			
		||||
    Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
 | 
			
		||||
    : ServiceFramework{system_, "vi:m"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
 | 
			
		||||
                                                                       hos_binder_driver_server} {
 | 
			
		||||
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"},
 | 
			
		||||
@@ -31,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_nvnflinger,
 | 
			
		||||
                                          m_hos_binder_driver_server, Permission::Manager, policy));
 | 
			
		||||
    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
 | 
			
		||||
                                          Permission::Manager, policy));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -10,29 +10,23 @@ namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
class Container;
 | 
			
		||||
class IApplicationDisplayService;
 | 
			
		||||
enum class Policy : u32;
 | 
			
		||||
 | 
			
		||||
class IManagerRootService final : public ServiceFramework<IManagerRootService> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IManagerRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
                                 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
 | 
			
		||||
    explicit IManagerRootService(Core::System& system_, std::shared_ptr<Container> container);
 | 
			
		||||
    ~IManagerRootService() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Result GetDisplayService(
 | 
			
		||||
        Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
 | 
			
		||||
        Policy policy);
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
 | 
			
		||||
private:
 | 
			
		||||
    const std::shared_ptr<Container> m_container;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
 | 
			
		||||
 | 
			
		||||
Result GetApplicationDisplayService(
 | 
			
		||||
    std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
 | 
			
		||||
    Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, 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, nvnflinger, hos_binder_driver_server);
 | 
			
		||||
        std::make_shared<IApplicationDisplayService>(system, std::move(container));
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,23 +11,18 @@ namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 | 
			
		||||
union Result;
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
class Container;
 | 
			
		||||
class IApplicationDisplayService;
 | 
			
		||||
enum class Permission;
 | 
			
		||||
enum class Policy : u32;
 | 
			
		||||
 | 
			
		||||
Result GetApplicationDisplayService(
 | 
			
		||||
    std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
 | 
			
		||||
    Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission,
 | 
			
		||||
    Core::System& system, std::shared_ptr<Container> container, Permission permission,
 | 
			
		||||
    Policy policy);
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -9,15 +9,15 @@
 | 
			
		||||
#include "core/hle/service/nvdrv/devices/nvmap.h"
 | 
			
		||||
#include "core/hle/service/nvdrv/nvdrv.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/pixel_format.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.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"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
@@ -26,7 +26,6 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_
 | 
			
		||||
    using Core::Memory::YUZU_PAGESIZE;
 | 
			
		||||
 | 
			
		||||
    // Allocate memory for the system shared buffer.
 | 
			
		||||
    // FIXME: This memory belongs to vi's .data section.
 | 
			
		||||
    auto& kernel = system.Kernel();
 | 
			
		||||
 | 
			
		||||
    // Hold a temporary page group reference while we try to map it.
 | 
			
		||||
@@ -204,15 +203,15 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
 | 
			
		||||
                                           std::shared_ptr<Nvidia::Module> nvdrv)
 | 
			
		||||
    : m_system(system), m_flinger(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,
 | 
			
		||||
                                        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_flinger.CreateLayer(m_display_id, blending).value();
 | 
			
		||||
    m_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_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_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_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;
 | 
			
		||||
 | 
			
		||||
@@ -444,4 +436,4 @@ Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
@@ -8,15 +8,27 @@
 | 
			
		||||
#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::Nvnflinger {
 | 
			
		||||
namespace Service::Nvidia {
 | 
			
		||||
class Module;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
union Result;
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
class Container;
 | 
			
		||||
 | 
			
		||||
struct SharedMemorySlot {
 | 
			
		||||
    u64 buffer_offset;
 | 
			
		||||
@@ -32,17 +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, Nvnflinger& 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, 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,
 | 
			
		||||
@@ -51,32 +63,30 @@ 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;
 | 
			
		||||
    Nvnflinger& m_flinger;
 | 
			
		||||
    std::shared_ptr<Nvidia::Module> m_nvdrv;
 | 
			
		||||
    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 = {};
 | 
			
		||||
    u32 buffer_nvmap_handle = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
@@ -3,15 +3,15 @@
 | 
			
		||||
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/hle/service/cmif_serialization.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.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_,
 | 
			
		||||
                                             Nvnflinger::Nvnflinger& nvnflinger)
 | 
			
		||||
    : ServiceFramework{system_, "ISystemDisplayService"}, m_nvnflinger{nvnflinger} {
 | 
			
		||||
                                             std::shared_ptr<Container> container)
 | 
			
		||||
    : ServiceFramework{system_, "ISystemDisplayService"}, m_container{std::move(container)} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {1200, nullptr, "GetZOrderCountMin"},
 | 
			
		||||
@@ -29,7 +29,7 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_,
 | 
			
		||||
        {2400, nullptr, "OpenIndirectLayer"},
 | 
			
		||||
        {2401, nullptr, "CloseIndirectLayer"},
 | 
			
		||||
        {2402, nullptr, "FlipIndirectLayer"},
 | 
			
		||||
        {3000, nullptr, "ListDisplayModes"},
 | 
			
		||||
        {3000, C<&ISystemDisplayService::ListDisplayModes>, "ListDisplayModes"},
 | 
			
		||||
        {3001, nullptr, "ListDisplayRgbRanges"},
 | 
			
		||||
        {3002, nullptr, "ListDisplayContentTypes"},
 | 
			
		||||
        {3200, C<&ISystemDisplayService::GetDisplayMode>, "GetDisplayMode"},
 | 
			
		||||
@@ -59,7 +59,7 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_,
 | 
			
		||||
        {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
 | 
			
		||||
@@ -80,31 +80,50 @@ Result ISystemDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISystemDisplayService::GetDisplayMode(Out<u32> out_width, Out<u32> out_height,
 | 
			
		||||
                                             Out<f32> out_refresh_rate, Out<u32> out_unknown) {
 | 
			
		||||
    LOG_WARNING(Service_VI, "(STUBBED) called");
 | 
			
		||||
Result ISystemDisplayService::ListDisplayModes(
 | 
			
		||||
    Out<u64> out_count, u64 display_id,
 | 
			
		||||
    OutArray<DisplayMode, BufferAttr_HipcMapAlias> out_display_modes) {
 | 
			
		||||
    LOG_WARNING(Service_VI, "(STUBBED) called, display_id={}", display_id);
 | 
			
		||||
 | 
			
		||||
    if (Settings::IsDockedMode()) {
 | 
			
		||||
        *out_width = static_cast<u32>(DisplayResolution::DockedWidth);
 | 
			
		||||
        *out_height = static_cast<u32>(DisplayResolution::DockedHeight);
 | 
			
		||||
    if (!out_display_modes.empty()) {
 | 
			
		||||
        out_display_modes[0] = {
 | 
			
		||||
            .width = 1920,
 | 
			
		||||
            .height = 1080,
 | 
			
		||||
            .refresh_rate = 60.f,
 | 
			
		||||
            .unknown = {},
 | 
			
		||||
        };
 | 
			
		||||
        *out_count = 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        *out_width = static_cast<u32>(DisplayResolution::UndockedWidth);
 | 
			
		||||
        *out_height = static_cast<u32>(DisplayResolution::UndockedHeight);
 | 
			
		||||
        *out_count = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out_refresh_rate = 60.f; // This wouldn't seem to be correct for 30 fps games.
 | 
			
		||||
    *out_unknown = 0;
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISystemDisplayService::GetDisplayMode(Out<DisplayMode> out_display_mode, u64 display_id) {
 | 
			
		||||
    LOG_WARNING(Service_VI, "(STUBBED) called, display_id={}", display_id);
 | 
			
		||||
 | 
			
		||||
    if (Settings::IsDockedMode()) {
 | 
			
		||||
        out_display_mode->width = static_cast<u32>(DisplayResolution::DockedWidth);
 | 
			
		||||
        out_display_mode->height = static_cast<u32>(DisplayResolution::DockedHeight);
 | 
			
		||||
    } else {
 | 
			
		||||
        out_display_mode->width = static_cast<u32>(DisplayResolution::UndockedWidth);
 | 
			
		||||
        out_display_mode->height = static_cast<u32>(DisplayResolution::UndockedHeight);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    out_display_mode->refresh_rate = 60.f; // This wouldn't seem to be correct for 30 fps games.
 | 
			
		||||
    out_display_mode->unknown = 0;
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ISystemDisplayService::GetSharedBufferMemoryHandleId(
 | 
			
		||||
    Out<s32> out_nvmap_handle, Out<u64> out_size,
 | 
			
		||||
    OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
 | 
			
		||||
    u64 buffer_id, ClientAppletResourceUserId aruid) {
 | 
			
		||||
    OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, u64 buffer_id,
 | 
			
		||||
    ClientAppletResourceUserId aruid) {
 | 
			
		||||
    LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid);
 | 
			
		||||
 | 
			
		||||
    R_RETURN(m_nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
 | 
			
		||||
    R_RETURN(m_container->GetSharedBufferManager()->GetSharedBufferMemoryHandleId(
 | 
			
		||||
        out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -122,7 +141,7 @@ 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_nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer(
 | 
			
		||||
    R_RETURN(m_container->GetSharedBufferManager()->AcquireSharedFrameBuffer(
 | 
			
		||||
        out_fence, *out_slots, out_target_slot, layer_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -131,15 +150,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_nvnflinger.GetSystemBufferManager().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_nvnflinger.GetSystemBufferManager().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
 | 
			
		||||
 
 | 
			
		||||
@@ -5,27 +5,28 @@
 | 
			
		||||
#include "core/hle/service/cmif_types.h"
 | 
			
		||||
#include "core/hle/service/nvnflinger/ui/fence.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
struct SharedMemoryPoolLayout;
 | 
			
		||||
}
 | 
			
		||||
#include "core/hle/service/vi/shared_buffer_manager.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
struct DisplayMode;
 | 
			
		||||
 | 
			
		||||
class Container;
 | 
			
		||||
 | 
			
		||||
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
 | 
			
		||||
    explicit ISystemDisplayService(Core::System& system_, std::shared_ptr<Container> container);
 | 
			
		||||
    ~ISystemDisplayService() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Result SetLayerZ(u32 z_value, u64 layer_id);
 | 
			
		||||
    Result SetLayerVisibility(bool visible, u64 layer_id);
 | 
			
		||||
    Result GetDisplayMode(Out<u32> out_width, Out<u32> out_height, Out<f32> out_refresh_rate,
 | 
			
		||||
                          Out<u32> out_unknown);
 | 
			
		||||
    Result ListDisplayModes(Out<u64> out_count, u64 display_id,
 | 
			
		||||
                            OutArray<DisplayMode, BufferAttr_HipcMapAlias> out_display_modes);
 | 
			
		||||
    Result GetDisplayMode(Out<DisplayMode> out_display_mode, u64 display_id);
 | 
			
		||||
 | 
			
		||||
    Result GetSharedBufferMemoryHandleId(
 | 
			
		||||
        Out<s32> out_nvmap_handle, Out<u64> out_size,
 | 
			
		||||
        OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
 | 
			
		||||
        OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
 | 
			
		||||
        u64 buffer_id, ClientAppletResourceUserId aruid);
 | 
			
		||||
    Result OpenSharedLayer(u64 layer_id);
 | 
			
		||||
    Result ConnectSharedLayer(u64 layer_id);
 | 
			
		||||
@@ -37,9 +38,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:
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    const std::shared_ptr<Container> m_container;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -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,10 +11,8 @@
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
ISystemRootService::ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
                                       Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
 | 
			
		||||
    : ServiceFramework{system_, "vi:s"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
 | 
			
		||||
                                                                       hos_binder_driver_server} {
 | 
			
		||||
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"},
 | 
			
		||||
@@ -26,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_nvnflinger,
 | 
			
		||||
                                          m_hos_binder_driver_server, Permission::System, policy));
 | 
			
		||||
    R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
 | 
			
		||||
                                          Permission::System, policy));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -10,20 +10,15 @@ namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
class Container;
 | 
			
		||||
class IApplicationDisplayService;
 | 
			
		||||
enum class Policy : u32;
 | 
			
		||||
 | 
			
		||||
class ISystemRootService final : public ServiceFramework<ISystemRootService> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
                                Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
 | 
			
		||||
    explicit ISystemRootService(Core::System& system_, std::shared_ptr<Container> container);
 | 
			
		||||
    ~ISystemRootService() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -31,8 +26,7 @@ private:
 | 
			
		||||
        Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
 | 
			
		||||
        Policy policy);
 | 
			
		||||
 | 
			
		||||
    Nvnflinger::Nvnflinger& m_nvnflinger;
 | 
			
		||||
    Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
 | 
			
		||||
    const std::shared_ptr<Container> m_container;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -1,25 +1,30 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/service/server_manager.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/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, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
                 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) {
 | 
			
		||||
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, nvnflinger, hos_binder_driver_server));
 | 
			
		||||
    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:s", std::make_shared<ISystemRootService>(system, nvnflinger, hos_binder_driver_server));
 | 
			
		||||
    server_manager->RegisterNamedService("vi:u", std::make_shared<IApplicationRootService>(
 | 
			
		||||
                                                     system, nvnflinger, hos_binder_driver_server));
 | 
			
		||||
        "vi:u", std::make_shared<IApplicationRootService>(system, container));
 | 
			
		||||
 | 
			
		||||
    std::stop_callback cb(token, [=] { container->OnTerminate(); });
 | 
			
		||||
 | 
			
		||||
    ServerManager::RunServer(std::move(server_manager));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,18 +3,14 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::Nvnflinger {
 | 
			
		||||
class HosBinderDriverServer;
 | 
			
		||||
class Nvnflinger;
 | 
			
		||||
} // namespace Service::Nvnflinger
 | 
			
		||||
 | 
			
		||||
namespace Service::VI {
 | 
			
		||||
 | 
			
		||||
void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
 | 
			
		||||
                 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
 | 
			
		||||
void LoopProcess(Core::System& system, std::stop_token token);
 | 
			
		||||
 | 
			
		||||
} // namespace Service::VI
 | 
			
		||||
 
 | 
			
		||||
@@ -66,9 +66,17 @@ struct DisplayInfo {
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
 | 
			
		||||
 | 
			
		||||
struct DisplayMode {
 | 
			
		||||
    u32 width;
 | 
			
		||||
    u32 height;
 | 
			
		||||
    f32 refresh_rate;
 | 
			
		||||
    u32 unknown;
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(DisplayMode) == 0x10, "DisplayMode 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:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								src/core/hle/service/vi/vsync_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/core/hle/service/vi/vsync_manager.cpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										29
									
								
								src/core/hle/service/vi/vsync_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/core/hle/service/vi/vsync_manager.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
		Reference in New Issue
	
	Block a user