summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvnflinger
diff options
context:
space:
mode:
authorNarr the Reg <juangerman-13@hotmail.com>2024-02-19 06:36:53 +0100
committerGitHub <noreply@github.com>2024-02-19 06:36:53 +0100
commit8615509c4054f497fbd6ed9a7adee5a998597905 (patch)
tree293bff8e944c2ca632524e39bbfba33d6475af16 /src/core/hle/service/nvnflinger
parentMerge pull request #13048 from liamwhite/new-shell (diff)
parentnvnflinger: check for layers before compose (diff)
downloadyuzu-8615509c4054f497fbd6ed9a7adee5a998597905.tar
yuzu-8615509c4054f497fbd6ed9a7adee5a998597905.tar.gz
yuzu-8615509c4054f497fbd6ed9a7adee5a998597905.tar.bz2
yuzu-8615509c4054f497fbd6ed9a7adee5a998597905.tar.lz
yuzu-8615509c4054f497fbd6ed9a7adee5a998597905.tar.xz
yuzu-8615509c4054f497fbd6ed9a7adee5a998597905.tar.zst
yuzu-8615509c4054f497fbd6ed9a7adee5a998597905.zip
Diffstat (limited to 'src/core/hle/service/nvnflinger')
-rw-r--r--src/core/hle/service/nvnflinger/binder.h23
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item_consumer.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item_consumer.h2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp76
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.h10
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp32
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.h8
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.h4
-rw-r--r--src/core/hle/service/nvnflinger/display.h55
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp447
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.h82
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp65
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.h20
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver.cpp66
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver.h46
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp22
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver_server.h16
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp333
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h166
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.cpp124
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.h65
22 files changed, 548 insertions, 1118 deletions
diff --git a/src/core/hle/service/nvnflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h
index 179938192..124accb94 100644
--- a/src/core/hle/service/nvnflinger/binder.h
+++ b/src/core/hle/service/nvnflinger/binder.h
@@ -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
diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
index cf151ea3a..123507123 100644
--- a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
@@ -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,
diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.h b/src/core/hle/service/nvnflinger/buffer_item_consumer.h
index e0c6b3604..9f95c9280 100644
--- a/src/core/hle/service/nvnflinger/buffer_item_consumer.h
+++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.h
@@ -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);
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
index bbe8e06d4..3bc23aa97 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
@@ -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
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
index 0a61e8dbd..a9226f1c3 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
@@ -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;
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index ec83beb9b..9e5091eeb 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -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
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
index 4682b0f84..048523514 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
@@ -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);
diff --git a/src/core/hle/service/nvnflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp
index 1059e72bf..e360ebfd8 100644
--- a/src/core/hle/service/nvnflinger/consumer_base.cpp
+++ b/src/core/hle/service/nvnflinger/consumer_base.cpp
@@ -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() {
diff --git a/src/core/hle/service/nvnflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h
index ea3e9e97a..b29c16f86 100644
--- a/src/core/hle/service/nvnflinger/consumer_base.h
+++ b/src/core/hle/service/nvnflinger/consumer_base.h
@@ -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;
};
diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h
new file mode 100644
index 000000000..f27cbf144
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/display.h
@@ -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
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
deleted file mode 100644
index 90f7248a0..000000000
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ /dev/null
@@ -1,447 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <random>
-
-#include "core/core.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/k_system_resource.h"
-#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/vi_results.h"
-#include "video_core/gpu.h"
-#include "video_core/host1x/host1x.h"
-
-namespace Service::Nvnflinger {
-
-namespace {
-
-Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_group,
- Core::System& system, u32 size) {
- 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.
- auto pg = std::make_unique<Kernel::KPageGroup>(
- kernel, std::addressof(kernel.GetSystemSystemResource().GetBlockInfoManager()));
-
- // Allocate memory from secure pool.
- R_TRY(kernel.MemoryManager().AllocateAndOpen(
- pg.get(), size / YUZU_PAGESIZE,
- Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
- Kernel::KMemoryManager::Direction::FromBack)));
-
- // Fill the output data with red.
- for (auto& block : *pg) {
- u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
- u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
-
- for (; start < end; start++) {
- *start = 0xFF0000FF;
- }
- }
-
- // Return the mapped page group.
- *out_page_group = std::move(pg);
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address,
- std::unique_ptr<Kernel::KPageGroup>& pg,
- Kernel::KProcess* process, Core::System& system) {
- using Core::Memory::YUZU_PAGESIZE;
-
- auto& page_table = process->GetPageTable();
-
- // Get bounds of where mapping is possible.
- const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
- const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
- const auto state = Kernel::KMemoryState::IoMemory;
- const auto perm = Kernel::KMemoryPermission::UserReadWrite;
- std::mt19937_64 rng{process->GetRandomEntropy(0)};
-
- // Retry up to 64 times to map into alias code range.
- Result res = ResultSuccess;
- int i;
- for (i = 0; i < 64; i++) {
- *out_map_address = alias_code_begin + ((rng() % alias_code_size) * YUZU_PAGESIZE);
- res = page_table.MapPageGroup(*out_map_address, *pg, state, perm);
- if (R_SUCCEEDED(res)) {
- break;
- }
- }
-
- // Return failure, if necessary
- R_UNLESS(i < 64, res);
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
- // Create a handle.
- Nvidia::Devices::nvmap::IocCreateParams create_params{
- .size = size,
- .handle = 0,
- };
- R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success,
- VI::ResultOperationFailed);
-
- // Assign the output handle.
- *out_nv_map_handle = create_params.handle;
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) {
- // Free the handle.
- Nvidia::Devices::nvmap::IocFreeParams free_params{
- .handle = handle,
- };
- R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success,
- VI::ResultOperationFailed);
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
- u32 size, Nvidia::DeviceFD nvmap_fd) {
- // Assign the allocated memory to the handle.
- Nvidia::Devices::nvmap::IocAllocParams alloc_params{
- .handle = handle,
- .heap_mask = 0,
- .flags = {},
- .align = 0,
- .kind = 0,
- .address = GetInteger(buffer),
- };
- R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success,
- VI::ResultOperationFailed);
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd,
- Common::ProcessAddress buffer, u32 size) {
- // Get the nvmap device.
- auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
- ASSERT(nvmap != nullptr);
-
- // Create a handle.
- R_TRY(CreateNvMapHandle(out_handle, *nvmap, size));
-
- // Ensure we maintain a clean state on failure.
- ON_RESULT_FAILURE {
- R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd));
- };
-
- // Assign the allocated memory to the handle.
- R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));
-}
-
-void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) {
- auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
- ASSERT(nvmap != nullptr);
-
- R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd));
-}
-
-constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
-constexpr u32 SharedBufferBlockLinearBpp = 4;
-
-constexpr u32 SharedBufferBlockLinearWidth = 1280;
-constexpr u32 SharedBufferBlockLinearHeight = 768;
-constexpr u32 SharedBufferBlockLinearStride =
- SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp;
-constexpr u32 SharedBufferNumSlots = 7;
-
-constexpr u32 SharedBufferWidth = 1280;
-constexpr u32 SharedBufferHeight = 720;
-constexpr u32 SharedBufferAsync = false;
-
-constexpr u32 SharedBufferSlotSize =
- SharedBufferBlockLinearWidth * SharedBufferBlockLinearHeight * SharedBufferBlockLinearBpp;
-constexpr u32 SharedBufferSize = SharedBufferSlotSize * SharedBufferNumSlots;
-
-constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
- SharedMemoryPoolLayout layout{};
- layout.num_slots = SharedBufferNumSlots;
-
- for (u32 i = 0; i < SharedBufferNumSlots; i++) {
- layout.slots[i].buffer_offset = i * SharedBufferSlotSize;
- layout.slots[i].size = SharedBufferSlotSize;
- layout.slots[i].width = SharedBufferWidth;
- layout.slots[i].height = SharedBufferHeight;
- }
-
- return layout;
-}();
-
-void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
- auto buffer = std::make_shared<android::NvGraphicBuffer>();
- buffer->width = SharedBufferWidth;
- buffer->height = SharedBufferHeight;
- buffer->stride = SharedBufferBlockLinearStride;
- buffer->format = SharedBufferBlockLinearFormat;
- buffer->external_format = SharedBufferBlockLinearFormat;
- buffer->buffer_id = handle;
- buffer->offset = slot * SharedBufferSlotSize;
- ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
-}
-
-} // 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)) {}
-
-FbShareBufferManager::~FbShareBufferManager() = default;
-
-Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id,
- u64* out_layer_handle, u64 display_id,
- LayerBlending blending) {
- std::scoped_lock lk{m_guard};
-
- // Ensure we haven't already created.
- const u64 aruid = owner_process->GetProcessId();
- R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
-
- // Allocate memory for the shared buffer if needed.
- if (!m_buffer_page_group) {
- R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
- SharedBufferSize));
-
- // Record buffer id.
- m_buffer_id = m_next_buffer_id++;
-
- // Record display id.
- m_display_id = display_id;
- }
-
- // Map into process.
- Common::ProcessAddress map_address{};
- R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
- owner_process, m_system));
-
- // Create new session.
- auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{});
- auto& session = it->second;
-
- auto& container = m_nvdrv->GetContainer();
- session.session_id = container.OpenSession(owner_process);
- session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
-
- // Create an nvmap handle for the buffer and assign the memory to it.
- R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
- 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);
-
- // Get the layer.
- VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id);
- ASSERT(layer != nullptr);
-
- // 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);
-
- // Assign outputs.
- *out_buffer_id = m_buffer_id;
- *out_layer_handle = session.layer_id;
-
- // We succeeded.
- R_SUCCEED();
-}
-
-void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) {
- std::scoped_lock lk{m_guard};
-
- if (m_buffer_id == 0) {
- return;
- }
-
- const u64 aruid = owner_process->GetProcessId();
- const auto it = m_sessions.find(aruid);
- if (it == m_sessions.end()) {
- return;
- }
-
- auto& session = it->second;
-
- // Destroy the layer.
- m_flinger.DestroyLayer(session.layer_id);
-
- // Close nvmap handle.
- FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
-
- // Close nvmap device.
- m_nvdrv->Close(session.nvmap_fd);
-
- // Close session.
- auto& container = m_nvdrv->GetContainer();
- container.CloseSession(session.session_id);
-
- // Erase.
- 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) {
- std::scoped_lock lk{m_guard};
-
- R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
- R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
- R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound);
-
- *out_pool_layout = SharedBufferPoolLayout;
- *out_buffer_size = SharedBufferSize;
- *out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle;
-
- 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) {
- 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();
-
- // 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,
- VI::ResultOperationFailed);
-
- // Assign remaining outputs.
- *out_target_slot = slot;
- out_slot_indexes = {0, 1, -1, -1};
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result FbShareBufferManager::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();
-
- // Request to queue the buffer.
- std::shared_ptr<android::GraphicBuffer> 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);
- };
-
- // Queue the buffer to the producer.
- android::QueueBufferInput input{};
- android::QueueBufferOutput output{};
- input.crop = crop_region;
- 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)) ==
- android::Status::NoError,
- VI::ResultOperationFailed);
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
- 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();
-
- // Set the event.
- *out_event = std::addressof(producer.GetNativeHandle());
-
- // We succeeded.
- R_SUCCEED();
-}
-
-Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
- std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
- Common::ScratchBuffer<u32> scratch;
-
- // TODO: this could be optimized
- s64 e = -1280 * 768 * 4;
- for (auto& block : *m_buffer_page_group) {
- u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
- u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
-
- for (; start < end; start++) {
- *start = 0;
-
- if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
- *start = capture_buffer[e];
- }
- e++;
- }
-
- m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
- m_system.GPU().InvalidateRegion(addr, end - start);
- });
- }
-
- *out_was_written = true;
- *out_layer_index = 1;
- R_SUCCEED();
-}
-
-} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
deleted file mode 100644
index b79a7d23a..000000000
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <map>
-
-#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;
-}
-
-namespace Service::Nvnflinger {
-
-struct SharedMemorySlot {
- u64 buffer_offset;
- u64 size;
- s32 width;
- s32 height;
-};
-static_assert(sizeof(SharedMemorySlot) == 0x18, "SharedMemorySlot has wrong size");
-
-struct SharedMemoryPoolLayout {
- s32 num_slots;
- std::array<SharedMemorySlot, 0x10> slots;
-};
-static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
-
-struct FbShareSession;
-
-class FbShareBufferManager final {
-public:
- explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
- std::shared_ptr<Nvidia::Module> nvdrv);
- ~FbShareBufferManager();
-
- 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 GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
- SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
- u64 applet_resource_user_id);
- Result AcquireSharedFrameBuffer(android::Fence* out_fence, std::array<s32, 4>& out_slots,
- 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 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::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;
-};
-
-struct FbShareSession {
- Nvidia::DeviceFD nvmap_fd = {};
- Nvidia::NvCore::SessionId session_id = {};
- u64 layer_id = {};
- u32 buffer_nvmap_handle = 0;
-};
-
-} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
index be7eb97a3..02215a786 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.cpp
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -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;
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h
index 28392c512..c5b830468 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.h
+++ b/src/core/hle/service/nvnflinger/hardware_composer.h
@@ -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
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp
new file mode 100644
index 000000000..8629a2e89
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp
@@ -0,0 +1,66 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#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"
+
+namespace Service::Nvnflinger {
+
+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"},
+ {2, C<&IHOSBinderDriver::GetNativeHandle>, "GetNativeHandle"},
+ {3, C<&IHOSBinderDriver::TransactParcelAuto>, "TransactParcelAuto"},
+ };
+ RegisterHandlers(functions);
+}
+
+IHOSBinderDriver::~IHOSBinderDriver() = default;
+
+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);
+
+ const auto binder = m_server->TryGetBinder(binder_id);
+ R_SUCCEED_IF(binder == nullptr);
+
+ binder->Transact(transaction_id, parcel_data, parcel_reply, flags);
+
+ R_SUCCEED();
+}
+
+Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) {
+ LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={}, type={}", binder_id, addval, type);
+ R_SUCCEED();
+}
+
+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);
+
+ 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, 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::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver.h b/src/core/hle/service/nvnflinger/hos_binder_driver.h
new file mode 100644
index 000000000..b7fb07bd2
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver.h
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Nvnflinger {
+
+class HosBinderDriverServer;
+class SurfaceFlinger;
+
+class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
+public:
+ 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, 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, u32 transaction_id,
+ InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
+ OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags);
+
+private:
+ const std::shared_ptr<HosBinderDriverServer> m_server;
+ const std::shared_ptr<SurfaceFlinger> m_surface_flinger;
+};
+
+} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
index b86a79ec9..29addda44 100644
--- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
@@ -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};
+
+ binders.erase(binder_id);
+}
+
+std::shared_ptr<android::IBinder> HosBinderDriverServer::TryGetBinder(s32 id) const {
std::scoped_lock lk{lock};
- if (auto search = producers.find(id); search != producers.end()) {
- return search->second.get();
+ if (auto search = binders.find(id); search != binders.end()) {
+ return search->second;
}
return {};
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
index 58bb9469a..d72b50833 100644
--- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
@@ -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
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 687ccc9f9..9e3b68b8a 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -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);
- }
+void LoopProcess(Core::System& system) {
+ const auto binder_server = std::make_shared<HosBinderDriverServer>();
+ const auto surface_flinger = std::make_shared<SurfaceFlinger>(system, *binder_server);
- return *system_buffer_manager;
+ 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
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index 4cf4f069d..5c41f3013 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -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
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp
new file mode 100644
index 000000000..41a705717
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp
@@ -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
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h
new file mode 100644
index 000000000..d8c53fbda
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/surface_flinger.h
@@ -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