From 14378f5c168c453ab41bcf333578abef91ec53fe Mon Sep 17 00:00:00 2001 From: Zephyron Date: Sun, 26 Jan 2025 14:21:36 +1000 Subject: [PATCH] nvnflinger: Implement reference counting for binder objects Implements proper reference counting for binder objects based on the official documentation. This adds both weak and strong reference counting support to the IBinder interface and its implementations (BufferQueueProducer and BufferQueueConsumer). The implementation follows the documented behavior where: - type 0 affects weak references - type 1 affects strong references - During initialization: {addval=1, type=0} followed by {addval=1, type=1} - For onFirstRef: {addval=1, type=1} - For onLastStrongRef: {addval=-1, type=1} Reference counters are implemented using std::atomic to ensure thread safety. REFS: switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount --- src/core/hle/service/nvnflinger/binder.h | 18 ++++++++++++++++++ .../service/nvnflinger/buffer_queue_consumer.h | 11 +++++++++++ .../service/nvnflinger/buffer_queue_producer.h | 11 +++++++++++ .../service/nvnflinger/hos_binder_driver.cpp | 17 ++++++++++++++++- 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/nvnflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h index 124accb946..f9f326e3bf 100644 --- a/src/core/hle/service/nvnflinger/binder.h +++ b/src/core/hle/service/nvnflinger/binder.h @@ -26,6 +26,24 @@ public: virtual void Transact(u32 code, std::span parcel_data, std::span parcel_reply, u32 flags) = 0; virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0; + + virtual void AdjustWeakRefcount(s32 addval) = 0; + virtual void AdjustStrongRefcount(s32 addval) = 0; +}; + +class Binder { +public: + void AdjustWeakRefcount(s32 addval) { + m_weak_ref_count += addval; + } + + void AdjustStrongRefcount(s32 addval) { + m_strong_ref_count += addval; + } + +private: + std::atomic m_weak_ref_count{}; + std::atomic m_strong_ref_count{}; }; } // 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 a9226f1c35..7549ebe96f 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h @@ -8,6 +8,7 @@ #include #include +#include #include "common/common_types.h" #include "core/hle/service/nvnflinger/binder.h" @@ -36,9 +37,19 @@ public: Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; + void AdjustWeakRefcount(s32 addval) override { + m_weak_ref_count += addval; + } + + void AdjustStrongRefcount(s32 addval) override { + m_strong_ref_count += addval; + } + private: std::shared_ptr core; BufferQueueDefs::SlotsType& slots; + std::atomic m_weak_ref_count{}; + std::atomic m_strong_ref_count{}; }; } // 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 048523514c..6df0b9014b 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "common/common_funcs.h" #include "core/hle/service/nvdrv/nvdata.h" @@ -52,6 +53,14 @@ public: Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; + void AdjustWeakRefcount(s32 addval) override { + m_weak_ref_count += addval; + } + + void AdjustStrongRefcount(s32 addval) override { + m_strong_ref_count += addval; + } + public: Status RequestBuffer(s32 slot, std::shared_ptr* buf); Status SetBufferCount(s32 buffer_count); @@ -87,6 +96,8 @@ private: std::condition_variable_any callback_condition; Service::Nvidia::NvCore::NvMap& nvmap; + std::atomic m_weak_ref_count{}; + std::atomic m_strong_ref_count{}; }; } // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp index 8629a2e89b..8b1ac3ed81 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp @@ -5,6 +5,7 @@ #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 namespace Service::Nvnflinger { @@ -40,7 +41,21 @@ Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id, } Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) { - LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={}, type={}", binder_id, addval, type); + LOG_DEBUG(Service_VI, "called id={}, addval={}, type={}", binder_id, addval, type); + + const auto binder = m_server->TryGetBinder(binder_id); + R_SUCCEED_IF(binder == nullptr); + + // type 0 = weak reference, type 1 = strong reference + if (type == 0) { + binder->AdjustWeakRefcount(addval); + } else if (type == 1) { + binder->AdjustStrongRefcount(addval); + } else { + LOG_ERROR(Service_VI, "Invalid refcount type {}", type); + R_THROW(Kernel::ResultInvalidArgument); + } + R_SUCCEED(); }