// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/nvdrv_interface.h" #include "core/hle/service/nvnflinger/display.h" #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" #include "core/hle/service/nvnflinger/surface_flinger.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" #include "core/hle/service/nvnflinger/buffer_queue_core.h" #include "core/hle/service/nvnflinger/buffer_queue_producer.h" namespace Service::Nvnflinger { SurfaceFlinger::SurfaceFlinger(Core::System& system, HosBinderDriverServer& server) : m_system(system), m_server(server), m_context(m_system, "SurfaceFlinger") { nvdrv = m_system.ServiceManager().GetService("nvdrv:s", true)->GetModule(); disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); } SurfaceFlinger::~SurfaceFlinger() { nvdrv->Close(disp_fd); } void SurfaceFlinger::AddDisplay(u64 display_id) { m_displays.emplace_back(display_id); } void SurfaceFlinger::RemoveDisplay(u64 display_id) { std::erase_if(m_displays, [&](auto& display) { return display.id == display_id; }); } 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(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( m_server.TryGetBinder(consumer_binder_id)); if (!display || !binder) { return; } auto buffer_item_consumer = std::make_shared(std::move(binder)); buffer_item_consumer->Connect(false); display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id); } void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) { auto* const display = this->FindDisplay(display_id); if (!display) { return; } m_composer.RemoveLayerLocked(*display, consumer_binder_id); std::erase_if(display->stack.layers, [&](auto& layer) { return layer.consumer_id == consumer_binder_id; }); } void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) { if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { layer->visible = visible; return; } } void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { layer->blending = blending; return; } } Display* SurfaceFlinger::FindDisplay(u64 display_id) { for (auto& display : m_displays) { if (display.id == display_id) { return &display; } } return nullptr; } Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) { for (auto& display : m_displays) { if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) { return layer; } } return nullptr; } void SurfaceFlinger::CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id) { auto& nvmap = nvdrv->GetContainer().GetNvMapFile(); auto core = std::make_shared(); auto producer = std::make_shared(m_context, core, nvmap); auto consumer = std::make_shared(core); *out_consumer_binder_id = m_server.RegisterBinder(std::move(consumer)); *out_producer_binder_id = m_server.RegisterBinder(std::move(producer)); } void SurfaceFlinger::DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id) { m_server.UnregisterBinder(producer_binder_id); m_server.UnregisterBinder(consumer_binder_id); } } // namespace Service::Nvnflinger